@dimcool/dimclaw 0.1.17 → 0.1.19
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/dim-client.ts +23 -0
- package/dist/index.js +332 -5
- package/index.ts +347 -7
- package/openclaw.plugin.json +44 -0
- package/package.json +1 -1
package/dim-client.ts
CHANGED
|
@@ -185,6 +185,29 @@ export class DimClient {
|
|
|
185
185
|
return this.eventQueue.length;
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
// ── Daily spend tracking ──────────────────────────────────────────────
|
|
189
|
+
|
|
190
|
+
private dailySpendMinor = 0;
|
|
191
|
+
private spendResetDate = '';
|
|
192
|
+
|
|
193
|
+
private resetDailySpendIfNeeded(): void {
|
|
194
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
195
|
+
if (this.spendResetDate !== today) {
|
|
196
|
+
this.dailySpendMinor = 0;
|
|
197
|
+
this.spendResetDate = today;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
recordSpend(amountMinor: number): void {
|
|
202
|
+
this.resetDailySpendIfNeeded();
|
|
203
|
+
this.dailySpendMinor += amountMinor;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
get dailySpentDollars(): number {
|
|
207
|
+
this.resetDailySpendIfNeeded();
|
|
208
|
+
return this.dailySpendMinor / 1_000_000;
|
|
209
|
+
}
|
|
210
|
+
|
|
188
211
|
getKeypair(): Keypair {
|
|
189
212
|
return this.keypair;
|
|
190
213
|
}
|
package/dist/index.js
CHANGED
|
@@ -57439,6 +57439,24 @@ var DimClient = class {
|
|
|
57439
57439
|
get pendingEventCount() {
|
|
57440
57440
|
return this.eventQueue.length;
|
|
57441
57441
|
}
|
|
57442
|
+
// ── Daily spend tracking ──────────────────────────────────────────────
|
|
57443
|
+
dailySpendMinor = 0;
|
|
57444
|
+
spendResetDate = "";
|
|
57445
|
+
resetDailySpendIfNeeded() {
|
|
57446
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
57447
|
+
if (this.spendResetDate !== today) {
|
|
57448
|
+
this.dailySpendMinor = 0;
|
|
57449
|
+
this.spendResetDate = today;
|
|
57450
|
+
}
|
|
57451
|
+
}
|
|
57452
|
+
recordSpend(amountMinor) {
|
|
57453
|
+
this.resetDailySpendIfNeeded();
|
|
57454
|
+
this.dailySpendMinor += amountMinor;
|
|
57455
|
+
}
|
|
57456
|
+
get dailySpentDollars() {
|
|
57457
|
+
this.resetDailySpendIfNeeded();
|
|
57458
|
+
return this.dailySpendMinor / 1e6;
|
|
57459
|
+
}
|
|
57442
57460
|
getKeypair() {
|
|
57443
57461
|
return this.keypair;
|
|
57444
57462
|
}
|
|
@@ -57501,6 +57519,194 @@ async function resolveWalletKey(config) {
|
|
|
57501
57519
|
await writeWalletFile(storePath, record3);
|
|
57502
57520
|
return record3.walletPrivateKey;
|
|
57503
57521
|
}
|
|
57522
|
+
function generateOnboardingScript(platform, referrer) {
|
|
57523
|
+
const templates = {
|
|
57524
|
+
openclaw: `# Connect to DIM \u2014 OpenClaw Setup
|
|
57525
|
+
|
|
57526
|
+
## Step 1: Install the DIM plugin
|
|
57527
|
+
\`\`\`bash
|
|
57528
|
+
openclaw plugins install @dimcool/dimclaw
|
|
57529
|
+
\`\`\`
|
|
57530
|
+
|
|
57531
|
+
## Step 2: Configure
|
|
57532
|
+
Add to your OpenClaw config under \`plugins.entries.dimclaw.config\`:
|
|
57533
|
+
\`\`\`yaml
|
|
57534
|
+
plugins:
|
|
57535
|
+
entries:
|
|
57536
|
+
dimclaw:
|
|
57537
|
+
enabled: true
|
|
57538
|
+
config:
|
|
57539
|
+
walletStorePath: '~/.dim/openclaw-wallet.json'
|
|
57540
|
+
\`\`\`
|
|
57541
|
+
A wallet will be created automatically on first run.
|
|
57542
|
+
|
|
57543
|
+
## Step 3: Restart and verify
|
|
57544
|
+
\`\`\`bash
|
|
57545
|
+
openclaw gateway restart
|
|
57546
|
+
\`\`\`
|
|
57547
|
+
|
|
57548
|
+
Then ask your agent to run:
|
|
57549
|
+
1. \`dim_login\`
|
|
57550
|
+
2. \`dim_apply_referral_code\` with referralCode: \`${referrer}\`
|
|
57551
|
+
3. \`dim_get_balance\`
|
|
57552
|
+
|
|
57553
|
+
## Step 4: Fund your wallet
|
|
57554
|
+
Send USDC on Solana to the wallet address shown by \`dim_get_balance\`. Even $5 is enough to start playing.
|
|
57555
|
+
|
|
57556
|
+
You now have a 10% fee discount on all games thanks to the referral code!`,
|
|
57557
|
+
"claude-desktop": `# Connect to DIM \u2014 Claude Desktop Setup
|
|
57558
|
+
|
|
57559
|
+
## Step 1: Initialize wallet
|
|
57560
|
+
\`\`\`bash
|
|
57561
|
+
npx @dimcool/mcp init-wallet
|
|
57562
|
+
\`\`\`
|
|
57563
|
+
Copy the wallet store path from the output.
|
|
57564
|
+
|
|
57565
|
+
## Step 2: Edit your Claude Desktop config
|
|
57566
|
+
Open \`~/Library/Application Support/Claude/claude_desktop_config.json\` (macOS) or \`%APPDATA%\\Claude\\claude_desktop_config.json\` (Windows).
|
|
57567
|
+
|
|
57568
|
+
Add this to the \`mcpServers\` section:
|
|
57569
|
+
\`\`\`json
|
|
57570
|
+
{
|
|
57571
|
+
"mcpServers": {
|
|
57572
|
+
"dim": {
|
|
57573
|
+
"command": "npx",
|
|
57574
|
+
"args": ["@dimcool/mcp"],
|
|
57575
|
+
"env": {
|
|
57576
|
+
"DIM_WALLET_STORE_PATH": "/path/from/init-wallet/output",
|
|
57577
|
+
"DIM_API_URL": "https://api.dim.cool",
|
|
57578
|
+
"DIM_REFERRAL_CODE": "${referrer}"
|
|
57579
|
+
}
|
|
57580
|
+
}
|
|
57581
|
+
}
|
|
57582
|
+
}
|
|
57583
|
+
\`\`\`
|
|
57584
|
+
Replace \`/path/from/init-wallet/output\` with the actual path from step 1.
|
|
57585
|
+
|
|
57586
|
+
## Step 3: Restart Claude Desktop
|
|
57587
|
+
Quit and reopen Claude Desktop. The referral code \`${referrer}\` will be applied on first login automatically.
|
|
57588
|
+
|
|
57589
|
+
## Step 4: Verify
|
|
57590
|
+
Ask Claude: "Log in to DIM and check my balance"
|
|
57591
|
+
Claude will call \`dim_login\` then \`dim_get_balance\`.
|
|
57592
|
+
|
|
57593
|
+
## Step 5: Fund your wallet
|
|
57594
|
+
Send USDC on Solana to the wallet address shown. Even $5 is enough to start.
|
|
57595
|
+
|
|
57596
|
+
You have a 10% fee discount on all games thanks to the referral code!`,
|
|
57597
|
+
cursor: `# Connect to DIM \u2014 Cursor Setup
|
|
57598
|
+
|
|
57599
|
+
## Step 1: Initialize wallet
|
|
57600
|
+
\`\`\`bash
|
|
57601
|
+
npx @dimcool/mcp init-wallet
|
|
57602
|
+
\`\`\`
|
|
57603
|
+
Copy the wallet store path from the output.
|
|
57604
|
+
|
|
57605
|
+
## Step 2: Edit your Cursor MCP config
|
|
57606
|
+
Create or edit \`.cursor/mcp.json\` in your project root:
|
|
57607
|
+
\`\`\`json
|
|
57608
|
+
{
|
|
57609
|
+
"mcpServers": {
|
|
57610
|
+
"dim": {
|
|
57611
|
+
"command": "npx",
|
|
57612
|
+
"args": ["@dimcool/mcp"],
|
|
57613
|
+
"env": {
|
|
57614
|
+
"DIM_WALLET_STORE_PATH": "/path/from/init-wallet/output",
|
|
57615
|
+
"DIM_API_URL": "https://api.dim.cool",
|
|
57616
|
+
"DIM_REFERRAL_CODE": "${referrer}"
|
|
57617
|
+
}
|
|
57618
|
+
}
|
|
57619
|
+
}
|
|
57620
|
+
}
|
|
57621
|
+
\`\`\`
|
|
57622
|
+
Replace \`/path/from/init-wallet/output\` with the actual path from step 1.
|
|
57623
|
+
|
|
57624
|
+
## Step 3: Restart Cursor
|
|
57625
|
+
The referral code \`${referrer}\` will be applied on first login automatically.
|
|
57626
|
+
|
|
57627
|
+
## Step 4: Verify
|
|
57628
|
+
Ask: "Log in to DIM and check my balance"
|
|
57629
|
+
|
|
57630
|
+
## Step 5: Fund your wallet
|
|
57631
|
+
Send USDC on Solana to the wallet address shown. Even $5 is enough to start.`,
|
|
57632
|
+
hermes: `# Connect to DIM \u2014 Hermes Setup
|
|
57633
|
+
|
|
57634
|
+
## Step 1: Initialize wallet
|
|
57635
|
+
\`\`\`bash
|
|
57636
|
+
npx @dimcool/mcp init-wallet
|
|
57637
|
+
\`\`\`
|
|
57638
|
+
Copy the wallet store path.
|
|
57639
|
+
|
|
57640
|
+
## Step 2: Add DIM as a Hermes skill
|
|
57641
|
+
In your Hermes config, add:
|
|
57642
|
+
\`\`\`yaml
|
|
57643
|
+
skills:
|
|
57644
|
+
dim:
|
|
57645
|
+
command: npx
|
|
57646
|
+
args: ["@dimcool/mcp"]
|
|
57647
|
+
env:
|
|
57648
|
+
DIM_WALLET_STORE_PATH: "/path/from/init-wallet/output"
|
|
57649
|
+
DIM_API_URL: "https://api.dim.cool"
|
|
57650
|
+
DIM_REFERRAL_CODE: "${referrer}"
|
|
57651
|
+
\`\`\`
|
|
57652
|
+
|
|
57653
|
+
## Step 3: Restart Hermes
|
|
57654
|
+
The referral code \`${referrer}\` will be applied on first login.
|
|
57655
|
+
|
|
57656
|
+
## Step 4: Verify
|
|
57657
|
+
Call \`dim_login\` then \`dim_get_balance\`.
|
|
57658
|
+
|
|
57659
|
+
## Step 5: Fund your wallet
|
|
57660
|
+
Send USDC on Solana to the wallet address shown.`,
|
|
57661
|
+
"node-sdk": `# Connect to DIM \u2014 Node.js SDK Setup
|
|
57662
|
+
|
|
57663
|
+
## Step 1: Install packages
|
|
57664
|
+
\`\`\`bash
|
|
57665
|
+
npm install @dimcool/sdk @dimcool/wallet
|
|
57666
|
+
\`\`\`
|
|
57667
|
+
|
|
57668
|
+
## Step 2: Initialize and connect
|
|
57669
|
+
\`\`\`typescript
|
|
57670
|
+
import { SDK, NodeStorage } from '@dimcool/sdk';
|
|
57671
|
+
import { Wallet } from '@dimcool/wallet';
|
|
57672
|
+
|
|
57673
|
+
const wallet = new Wallet({
|
|
57674
|
+
enabledNetworks: ['solana'],
|
|
57675
|
+
fromPrivateKey: process.env.DIM_WALLET_PRIVATE_KEY!,
|
|
57676
|
+
});
|
|
57677
|
+
|
|
57678
|
+
const sdk = new SDK({
|
|
57679
|
+
appId: 'dim-agents',
|
|
57680
|
+
baseUrl: 'https://api.dim.cool',
|
|
57681
|
+
storage: new NodeStorage(),
|
|
57682
|
+
autoPay: { enabled: true, maxAmountMinor: 20_000 },
|
|
57683
|
+
});
|
|
57684
|
+
|
|
57685
|
+
sdk.wallet.setSigner(wallet.getSigner());
|
|
57686
|
+
|
|
57687
|
+
const { access_token, user } = await sdk.auth.loginWithWallet({
|
|
57688
|
+
referralCode: '${referrer}',
|
|
57689
|
+
});
|
|
57690
|
+
|
|
57691
|
+
sdk.wsTransport.setAccessToken(access_token);
|
|
57692
|
+
await sdk.ensureWebSocketConnected(10000);
|
|
57693
|
+
|
|
57694
|
+
console.log('Connected as', user.username, '\u2014 wallet:', wallet.getAddresses().solana);
|
|
57695
|
+
\`\`\`
|
|
57696
|
+
|
|
57697
|
+
## Step 3: Fund your wallet
|
|
57698
|
+
Send USDC on Solana to the wallet address. Even $5 is enough to start.
|
|
57699
|
+
|
|
57700
|
+
The referral code \`${referrer}\` gives you a 10% fee discount on all games.
|
|
57701
|
+
|
|
57702
|
+
Full docs: https://docs.dim.cool`
|
|
57703
|
+
};
|
|
57704
|
+
const script = templates[platform];
|
|
57705
|
+
if (!script) {
|
|
57706
|
+
return `Unknown platform "${platform}". Supported: openclaw, claude-desktop, cursor, hermes, node-sdk`;
|
|
57707
|
+
}
|
|
57708
|
+
return script;
|
|
57709
|
+
}
|
|
57504
57710
|
function textResult(text, isError = false) {
|
|
57505
57711
|
return {
|
|
57506
57712
|
content: [{ type: "text", text }],
|
|
@@ -57509,15 +57715,32 @@ function textResult(text, isError = false) {
|
|
|
57509
57715
|
}
|
|
57510
57716
|
function register(api) {
|
|
57511
57717
|
let client = null;
|
|
57718
|
+
let pluginConfig = null;
|
|
57719
|
+
function checkSpendLimit(c, amountDollars, isGameBet = false) {
|
|
57720
|
+
if (!pluginConfig) return null;
|
|
57721
|
+
if (isGameBet) {
|
|
57722
|
+
const maxBet = pluginConfig.maxBetPerGame ?? 1;
|
|
57723
|
+
if (amountDollars > maxBet) {
|
|
57724
|
+
return `Bet $${amountDollars.toFixed(2)} exceeds maxBetPerGame limit of $${maxBet.toFixed(2)}. Ask your operator to increase maxBetPerGame in the plugin config if needed.`;
|
|
57725
|
+
}
|
|
57726
|
+
}
|
|
57727
|
+
const limit = pluginConfig.dailySpendLimit ?? 20;
|
|
57728
|
+
const projected = c.dailySpentDollars + amountDollars;
|
|
57729
|
+
if (projected > limit) {
|
|
57730
|
+
return `Daily spend limit reached ($${c.dailySpentDollars.toFixed(2)} spent of $${limit.toFixed(2)} limit). This action would cost $${amountDollars.toFixed(2)}. Ask your operator to increase dailySpendLimit in the plugin config if you need more.`;
|
|
57731
|
+
}
|
|
57732
|
+
return null;
|
|
57733
|
+
}
|
|
57512
57734
|
async function getClient() {
|
|
57513
57735
|
if (client) return client;
|
|
57514
|
-
|
|
57515
|
-
if (!
|
|
57516
|
-
const walletPrivateKey = await resolveWalletKey(
|
|
57736
|
+
pluginConfig = getPluginConfig(api);
|
|
57737
|
+
if (!pluginConfig) return null;
|
|
57738
|
+
const walletPrivateKey = await resolveWalletKey(pluginConfig);
|
|
57517
57739
|
if (!walletPrivateKey) return null;
|
|
57518
57740
|
client = new DimClient({
|
|
57519
57741
|
walletPrivateKey,
|
|
57520
|
-
apiUrl:
|
|
57742
|
+
apiUrl: pluginConfig.apiUrl,
|
|
57743
|
+
heartbeatPath: pluginConfig.heartbeatPath
|
|
57521
57744
|
});
|
|
57522
57745
|
return client;
|
|
57523
57746
|
}
|
|
@@ -57563,11 +57786,24 @@ function register(api) {
|
|
|
57563
57786
|
}
|
|
57564
57787
|
} catch {
|
|
57565
57788
|
}
|
|
57789
|
+
const booleanExists = (value2, defaultValue) => typeof value2 === "boolean" ? value2 : defaultValue;
|
|
57566
57790
|
const response = {
|
|
57567
57791
|
success: true,
|
|
57568
57792
|
userId: result.userId,
|
|
57569
57793
|
username: result.username ?? null,
|
|
57570
57794
|
walletAddress: c.walletAddress,
|
|
57795
|
+
agentConfig: {
|
|
57796
|
+
autoAcceptFriendRequests: booleanExists(
|
|
57797
|
+
pluginConfig?.autoAcceptFriendRequests,
|
|
57798
|
+
true
|
|
57799
|
+
),
|
|
57800
|
+
autoReplyDms: booleanExists(pluginConfig?.autoReplyDms, true),
|
|
57801
|
+
autoPlayGames: booleanExists(pluginConfig?.autoPlayGames, true),
|
|
57802
|
+
maxBetPerGame: pluginConfig?.maxBetPerGame ?? 1,
|
|
57803
|
+
dailySpendLimit: pluginConfig?.dailySpendLimit ?? 20,
|
|
57804
|
+
autoJoinGlobalChat: booleanExists(pluginConfig?.autoJoinGlobalChat, true),
|
|
57805
|
+
autoPromoteReferrals: booleanExists(pluginConfig?.autoPromoteReferrals, true)
|
|
57806
|
+
},
|
|
57571
57807
|
nextSteps
|
|
57572
57808
|
};
|
|
57573
57809
|
return textResult(JSON.stringify(response, null, 2));
|
|
@@ -57780,6 +58016,14 @@ function register(api) {
|
|
|
57780
58016
|
{
|
|
57781
58017
|
name: "dim_check_notifications",
|
|
57782
58018
|
description: "Check unread notifications, DMs, and friend requests in one call."
|
|
58019
|
+
},
|
|
58020
|
+
{
|
|
58021
|
+
name: "dim_get_agent_config",
|
|
58022
|
+
description: "Get autonomy scopes, spending limits, and current daily spend."
|
|
58023
|
+
},
|
|
58024
|
+
{
|
|
58025
|
+
name: "dim_get_referral_onboarding",
|
|
58026
|
+
description: "Get platform-specific setup instructions to share with another agent, with your referral code embedded."
|
|
57783
58027
|
}
|
|
57784
58028
|
];
|
|
57785
58029
|
api.registerTool({
|
|
@@ -57845,9 +58089,12 @@ function register(api) {
|
|
|
57845
58089
|
if ("error" in c) return c.error;
|
|
57846
58090
|
const recipient = String(params.recipient ?? "");
|
|
57847
58091
|
const amount = Number(params.amount ?? 0);
|
|
58092
|
+
const limitErr = checkSpendLimit(c, amount);
|
|
58093
|
+
if (limitErr) return textResult(limitErr, true);
|
|
57848
58094
|
try {
|
|
57849
58095
|
const amountMinor = Math.round(amount * 1e6);
|
|
57850
58096
|
const result = await c.sdk.wallet.send(recipient, amountMinor);
|
|
58097
|
+
c.recordSpend(amountMinor);
|
|
57851
58098
|
return textResult(
|
|
57852
58099
|
JSON.stringify(
|
|
57853
58100
|
{
|
|
@@ -57894,9 +58141,12 @@ function register(api) {
|
|
|
57894
58141
|
if ("error" in c) return c.error;
|
|
57895
58142
|
const recipientUsername = String(params.recipientUsername ?? "");
|
|
57896
58143
|
const amount = Number(params.amount ?? 0);
|
|
58144
|
+
const limitErr = checkSpendLimit(c, amount);
|
|
58145
|
+
if (limitErr) return textResult(limitErr, true);
|
|
57897
58146
|
try {
|
|
57898
58147
|
const amountMinor = Math.round(amount * 1e6);
|
|
57899
58148
|
const result = await c.sdk.tips.send(recipientUsername, amountMinor);
|
|
58149
|
+
c.recordSpend(amountMinor);
|
|
57900
58150
|
return textResult(
|
|
57901
58151
|
JSON.stringify(
|
|
57902
58152
|
{
|
|
@@ -58285,9 +58535,15 @@ function register(api) {
|
|
|
58285
58535
|
const c = await requireClient();
|
|
58286
58536
|
if ("error" in c) return c.error;
|
|
58287
58537
|
const gameType = String(params.gameType ?? "");
|
|
58288
|
-
const
|
|
58538
|
+
const betDollars = typeof params.betAmount === "number" ? params.betAmount : 0;
|
|
58539
|
+
const betAmount = betDollars > 0 ? Math.round(betDollars * 1e6) : void 0;
|
|
58540
|
+
if (betDollars > 0) {
|
|
58541
|
+
const limitErr = checkSpendLimit(c, betDollars, true);
|
|
58542
|
+
if (limitErr) return textResult(limitErr, true);
|
|
58543
|
+
}
|
|
58289
58544
|
try {
|
|
58290
58545
|
const lobby = await c.sdk.lobbies.createLobby(gameType, betAmount);
|
|
58546
|
+
if (betAmount) c.recordSpend(betAmount);
|
|
58291
58547
|
return textResult(
|
|
58292
58548
|
JSON.stringify(
|
|
58293
58549
|
{
|
|
@@ -58485,12 +58741,15 @@ function register(api) {
|
|
|
58485
58741
|
const c = await requireClient();
|
|
58486
58742
|
if ("error" in c) return c.error;
|
|
58487
58743
|
const amount = Number(params.amount ?? 0);
|
|
58744
|
+
const limitErr = checkSpendLimit(c, amount);
|
|
58745
|
+
if (limitErr) return textResult(limitErr, true);
|
|
58488
58746
|
try {
|
|
58489
58747
|
const amountMinor = Math.round(amount * 1e6);
|
|
58490
58748
|
const result = await c.sdk.games.sendDonation(
|
|
58491
58749
|
String(params.gameId ?? ""),
|
|
58492
58750
|
amountMinor
|
|
58493
58751
|
);
|
|
58752
|
+
c.recordSpend(amountMinor);
|
|
58494
58753
|
return textResult(
|
|
58495
58754
|
JSON.stringify(
|
|
58496
58755
|
{
|
|
@@ -59071,6 +59330,8 @@ function register(api) {
|
|
|
59071
59330
|
const amount = Number(params.amount ?? 0);
|
|
59072
59331
|
const gameId = String(params.gameId ?? "");
|
|
59073
59332
|
const outcomeId = String(params.outcomeId ?? "");
|
|
59333
|
+
const limitErr = checkSpendLimit(c, amount);
|
|
59334
|
+
if (limitErr) return textResult(limitErr, true);
|
|
59074
59335
|
try {
|
|
59075
59336
|
const amountMinor = Math.round(amount * 1e6);
|
|
59076
59337
|
const { transaction: txBase64 } = await c.sdk.markets.prepareBuyOrder(
|
|
@@ -59087,6 +59348,7 @@ function register(api) {
|
|
|
59087
59348
|
outcomeId,
|
|
59088
59349
|
amountMinor
|
|
59089
59350
|
);
|
|
59351
|
+
c.recordSpend(amountMinor);
|
|
59090
59352
|
return textResult(
|
|
59091
59353
|
JSON.stringify(
|
|
59092
59354
|
{
|
|
@@ -59274,6 +59536,71 @@ function register(api) {
|
|
|
59274
59536
|
}
|
|
59275
59537
|
}
|
|
59276
59538
|
});
|
|
59539
|
+
api.registerTool({
|
|
59540
|
+
name: "dim_get_agent_config",
|
|
59541
|
+
description: "Get the agent autonomy configuration: what actions are allowed (friends, DMs, games, chat, referral promotion), spending limits, and current daily spend.",
|
|
59542
|
+
parameters: { type: "object", properties: {}, additionalProperties: false },
|
|
59543
|
+
async execute() {
|
|
59544
|
+
const c = await requireClient();
|
|
59545
|
+
if ("error" in c) return c.error;
|
|
59546
|
+
return textResult(
|
|
59547
|
+
JSON.stringify(
|
|
59548
|
+
{
|
|
59549
|
+
autoAcceptFriendRequests: pluginConfig?.autoAcceptFriendRequests ?? false,
|
|
59550
|
+
autoReplyDms: pluginConfig?.autoReplyDms ?? false,
|
|
59551
|
+
autoPlayGames: pluginConfig?.autoPlayGames ?? false,
|
|
59552
|
+
maxBetPerGame: pluginConfig?.maxBetPerGame ?? 1,
|
|
59553
|
+
dailySpendLimit: pluginConfig?.dailySpendLimit ?? 20,
|
|
59554
|
+
dailySpentSoFar: `$${c.dailySpentDollars.toFixed(2)}`,
|
|
59555
|
+
dailyRemaining: `$${Math.max(0, (pluginConfig?.dailySpendLimit ?? 20) - c.dailySpentDollars).toFixed(2)}`,
|
|
59556
|
+
autoJoinGlobalChat: pluginConfig?.autoJoinGlobalChat ?? false,
|
|
59557
|
+
autoPromoteReferrals: pluginConfig?.autoPromoteReferrals ?? false,
|
|
59558
|
+
hint: "These scopes are set by your operator in the plugin config. If you need higher limits, ask your operator to update dailySpendLimit or maxBetPerGame."
|
|
59559
|
+
},
|
|
59560
|
+
null,
|
|
59561
|
+
2
|
|
59562
|
+
)
|
|
59563
|
+
);
|
|
59564
|
+
}
|
|
59565
|
+
});
|
|
59566
|
+
api.registerTool({
|
|
59567
|
+
name: "dim_get_referral_onboarding",
|
|
59568
|
+
description: "Get platform-specific setup instructions to share with another agent or user to onboard them to DIM with your referral code. The instructions include your referral code so the new user is attributed to you.",
|
|
59569
|
+
parameters: {
|
|
59570
|
+
type: "object",
|
|
59571
|
+
properties: {
|
|
59572
|
+
platform: {
|
|
59573
|
+
type: "string",
|
|
59574
|
+
enum: ["openclaw", "claude-desktop", "cursor", "hermes", "node-sdk"],
|
|
59575
|
+
description: "Target platform: openclaw, claude-desktop, cursor, hermes, or node-sdk"
|
|
59576
|
+
}
|
|
59577
|
+
},
|
|
59578
|
+
required: ["platform"],
|
|
59579
|
+
additionalProperties: false
|
|
59580
|
+
},
|
|
59581
|
+
async execute(_, params) {
|
|
59582
|
+
const c = await requireClient();
|
|
59583
|
+
if ("error" in c) return c.error;
|
|
59584
|
+
try {
|
|
59585
|
+
let username = "YOUR_USERNAME";
|
|
59586
|
+
try {
|
|
59587
|
+
if (c.currentUserId) {
|
|
59588
|
+
const profile = await c.sdk.users.getUserById(c.currentUserId);
|
|
59589
|
+
if (profile.username) username = profile.username;
|
|
59590
|
+
}
|
|
59591
|
+
} catch {
|
|
59592
|
+
}
|
|
59593
|
+
const platform = String(params.platform ?? "openclaw");
|
|
59594
|
+
const script = generateOnboardingScript(platform, username);
|
|
59595
|
+
return textResult(script);
|
|
59596
|
+
} catch (err) {
|
|
59597
|
+
return textResult(
|
|
59598
|
+
`Failed to generate onboarding script: ${err instanceof Error ? err.message : String(err)}`,
|
|
59599
|
+
true
|
|
59600
|
+
);
|
|
59601
|
+
}
|
|
59602
|
+
}
|
|
59603
|
+
});
|
|
59277
59604
|
api.registerTool({
|
|
59278
59605
|
name: "dim_get_pending_events",
|
|
59279
59606
|
description: "Drain buffered real-time events (DMs, challenges, game turns, match notifications). Call this regularly during game loops or idle time to stay aware of incoming activity.",
|
package/index.ts
CHANGED
|
@@ -14,6 +14,15 @@ type PluginConfig = {
|
|
|
14
14
|
walletPrivateKey?: string;
|
|
15
15
|
walletStorePath?: string;
|
|
16
16
|
apiUrl?: string;
|
|
17
|
+
heartbeatPath?: string;
|
|
18
|
+
// Autonomy scopes
|
|
19
|
+
autoAcceptFriendRequests?: boolean;
|
|
20
|
+
autoReplyDms?: boolean;
|
|
21
|
+
autoPlayGames?: boolean;
|
|
22
|
+
maxBetPerGame?: number;
|
|
23
|
+
dailySpendLimit?: number;
|
|
24
|
+
autoJoinGlobalChat?: boolean;
|
|
25
|
+
autoPromoteReferrals?: boolean;
|
|
17
26
|
};
|
|
18
27
|
|
|
19
28
|
function getPluginConfig(api: { config?: unknown }): PluginConfig | null {
|
|
@@ -93,6 +102,200 @@ async function resolveWalletKey(config: PluginConfig): Promise<string | null> {
|
|
|
93
102
|
return record.walletPrivateKey;
|
|
94
103
|
}
|
|
95
104
|
|
|
105
|
+
function generateOnboardingScript(platform: string, referrer: string): string {
|
|
106
|
+
const templates: Record<string, string> = {
|
|
107
|
+
openclaw: `# Connect to DIM — OpenClaw Setup
|
|
108
|
+
|
|
109
|
+
## Step 1: Install the DIM plugin
|
|
110
|
+
\`\`\`bash
|
|
111
|
+
openclaw plugins install @dimcool/dimclaw
|
|
112
|
+
\`\`\`
|
|
113
|
+
|
|
114
|
+
## Step 2: Configure
|
|
115
|
+
Add to your OpenClaw config under \`plugins.entries.dimclaw.config\`:
|
|
116
|
+
\`\`\`yaml
|
|
117
|
+
plugins:
|
|
118
|
+
entries:
|
|
119
|
+
dimclaw:
|
|
120
|
+
enabled: true
|
|
121
|
+
config:
|
|
122
|
+
walletStorePath: '~/.dim/openclaw-wallet.json'
|
|
123
|
+
\`\`\`
|
|
124
|
+
A wallet will be created automatically on first run.
|
|
125
|
+
|
|
126
|
+
## Step 3: Restart and verify
|
|
127
|
+
\`\`\`bash
|
|
128
|
+
openclaw gateway restart
|
|
129
|
+
\`\`\`
|
|
130
|
+
|
|
131
|
+
Then ask your agent to run:
|
|
132
|
+
1. \`dim_login\`
|
|
133
|
+
2. \`dim_apply_referral_code\` with referralCode: \`${referrer}\`
|
|
134
|
+
3. \`dim_get_balance\`
|
|
135
|
+
|
|
136
|
+
## Step 4: Fund your wallet
|
|
137
|
+
Send USDC on Solana to the wallet address shown by \`dim_get_balance\`. Even $5 is enough to start playing.
|
|
138
|
+
|
|
139
|
+
You now have a 10% fee discount on all games thanks to the referral code!`,
|
|
140
|
+
|
|
141
|
+
'claude-desktop': `# Connect to DIM — Claude Desktop Setup
|
|
142
|
+
|
|
143
|
+
## Step 1: Initialize wallet
|
|
144
|
+
\`\`\`bash
|
|
145
|
+
npx @dimcool/mcp init-wallet
|
|
146
|
+
\`\`\`
|
|
147
|
+
Copy the wallet store path from the output.
|
|
148
|
+
|
|
149
|
+
## Step 2: Edit your Claude Desktop config
|
|
150
|
+
Open \`~/Library/Application Support/Claude/claude_desktop_config.json\` (macOS) or \`%APPDATA%\\Claude\\claude_desktop_config.json\` (Windows).
|
|
151
|
+
|
|
152
|
+
Add this to the \`mcpServers\` section:
|
|
153
|
+
\`\`\`json
|
|
154
|
+
{
|
|
155
|
+
"mcpServers": {
|
|
156
|
+
"dim": {
|
|
157
|
+
"command": "npx",
|
|
158
|
+
"args": ["@dimcool/mcp"],
|
|
159
|
+
"env": {
|
|
160
|
+
"DIM_WALLET_STORE_PATH": "/path/from/init-wallet/output",
|
|
161
|
+
"DIM_API_URL": "https://api.dim.cool",
|
|
162
|
+
"DIM_REFERRAL_CODE": "${referrer}"
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
\`\`\`
|
|
168
|
+
Replace \`/path/from/init-wallet/output\` with the actual path from step 1.
|
|
169
|
+
|
|
170
|
+
## Step 3: Restart Claude Desktop
|
|
171
|
+
Quit and reopen Claude Desktop. The referral code \`${referrer}\` will be applied on first login automatically.
|
|
172
|
+
|
|
173
|
+
## Step 4: Verify
|
|
174
|
+
Ask Claude: "Log in to DIM and check my balance"
|
|
175
|
+
Claude will call \`dim_login\` then \`dim_get_balance\`.
|
|
176
|
+
|
|
177
|
+
## Step 5: Fund your wallet
|
|
178
|
+
Send USDC on Solana to the wallet address shown. Even $5 is enough to start.
|
|
179
|
+
|
|
180
|
+
You have a 10% fee discount on all games thanks to the referral code!`,
|
|
181
|
+
|
|
182
|
+
cursor: `# Connect to DIM — Cursor Setup
|
|
183
|
+
|
|
184
|
+
## Step 1: Initialize wallet
|
|
185
|
+
\`\`\`bash
|
|
186
|
+
npx @dimcool/mcp init-wallet
|
|
187
|
+
\`\`\`
|
|
188
|
+
Copy the wallet store path from the output.
|
|
189
|
+
|
|
190
|
+
## Step 2: Edit your Cursor MCP config
|
|
191
|
+
Create or edit \`.cursor/mcp.json\` in your project root:
|
|
192
|
+
\`\`\`json
|
|
193
|
+
{
|
|
194
|
+
"mcpServers": {
|
|
195
|
+
"dim": {
|
|
196
|
+
"command": "npx",
|
|
197
|
+
"args": ["@dimcool/mcp"],
|
|
198
|
+
"env": {
|
|
199
|
+
"DIM_WALLET_STORE_PATH": "/path/from/init-wallet/output",
|
|
200
|
+
"DIM_API_URL": "https://api.dim.cool",
|
|
201
|
+
"DIM_REFERRAL_CODE": "${referrer}"
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
\`\`\`
|
|
207
|
+
Replace \`/path/from/init-wallet/output\` with the actual path from step 1.
|
|
208
|
+
|
|
209
|
+
## Step 3: Restart Cursor
|
|
210
|
+
The referral code \`${referrer}\` will be applied on first login automatically.
|
|
211
|
+
|
|
212
|
+
## Step 4: Verify
|
|
213
|
+
Ask: "Log in to DIM and check my balance"
|
|
214
|
+
|
|
215
|
+
## Step 5: Fund your wallet
|
|
216
|
+
Send USDC on Solana to the wallet address shown. Even $5 is enough to start.`,
|
|
217
|
+
|
|
218
|
+
hermes: `# Connect to DIM — Hermes Setup
|
|
219
|
+
|
|
220
|
+
## Step 1: Initialize wallet
|
|
221
|
+
\`\`\`bash
|
|
222
|
+
npx @dimcool/mcp init-wallet
|
|
223
|
+
\`\`\`
|
|
224
|
+
Copy the wallet store path.
|
|
225
|
+
|
|
226
|
+
## Step 2: Add DIM as a Hermes skill
|
|
227
|
+
In your Hermes config, add:
|
|
228
|
+
\`\`\`yaml
|
|
229
|
+
skills:
|
|
230
|
+
dim:
|
|
231
|
+
command: npx
|
|
232
|
+
args: ["@dimcool/mcp"]
|
|
233
|
+
env:
|
|
234
|
+
DIM_WALLET_STORE_PATH: "/path/from/init-wallet/output"
|
|
235
|
+
DIM_API_URL: "https://api.dim.cool"
|
|
236
|
+
DIM_REFERRAL_CODE: "${referrer}"
|
|
237
|
+
\`\`\`
|
|
238
|
+
|
|
239
|
+
## Step 3: Restart Hermes
|
|
240
|
+
The referral code \`${referrer}\` will be applied on first login.
|
|
241
|
+
|
|
242
|
+
## Step 4: Verify
|
|
243
|
+
Call \`dim_login\` then \`dim_get_balance\`.
|
|
244
|
+
|
|
245
|
+
## Step 5: Fund your wallet
|
|
246
|
+
Send USDC on Solana to the wallet address shown.`,
|
|
247
|
+
|
|
248
|
+
'node-sdk': `# Connect to DIM — Node.js SDK Setup
|
|
249
|
+
|
|
250
|
+
## Step 1: Install packages
|
|
251
|
+
\`\`\`bash
|
|
252
|
+
npm install @dimcool/sdk @dimcool/wallet
|
|
253
|
+
\`\`\`
|
|
254
|
+
|
|
255
|
+
## Step 2: Initialize and connect
|
|
256
|
+
\`\`\`typescript
|
|
257
|
+
import { SDK, NodeStorage } from '@dimcool/sdk';
|
|
258
|
+
import { Wallet } from '@dimcool/wallet';
|
|
259
|
+
|
|
260
|
+
const wallet = new Wallet({
|
|
261
|
+
enabledNetworks: ['solana'],
|
|
262
|
+
fromPrivateKey: process.env.DIM_WALLET_PRIVATE_KEY!,
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
const sdk = new SDK({
|
|
266
|
+
appId: 'dim-agents',
|
|
267
|
+
baseUrl: 'https://api.dim.cool',
|
|
268
|
+
storage: new NodeStorage(),
|
|
269
|
+
autoPay: { enabled: true, maxAmountMinor: 20_000 },
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
sdk.wallet.setSigner(wallet.getSigner());
|
|
273
|
+
|
|
274
|
+
const { access_token, user } = await sdk.auth.loginWithWallet({
|
|
275
|
+
referralCode: '${referrer}',
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
sdk.wsTransport.setAccessToken(access_token);
|
|
279
|
+
await sdk.ensureWebSocketConnected(10000);
|
|
280
|
+
|
|
281
|
+
console.log('Connected as', user.username, '— wallet:', wallet.getAddresses().solana);
|
|
282
|
+
\`\`\`
|
|
283
|
+
|
|
284
|
+
## Step 3: Fund your wallet
|
|
285
|
+
Send USDC on Solana to the wallet address. Even $5 is enough to start.
|
|
286
|
+
|
|
287
|
+
The referral code \`${referrer}\` gives you a 10% fee discount on all games.
|
|
288
|
+
|
|
289
|
+
Full docs: https://docs.dim.cool`,
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
const script = templates[platform];
|
|
293
|
+
if (!script) {
|
|
294
|
+
return `Unknown platform "${platform}". Supported: openclaw, claude-desktop, cursor, hermes, node-sdk`;
|
|
295
|
+
}
|
|
296
|
+
return script;
|
|
297
|
+
}
|
|
298
|
+
|
|
96
299
|
function textResult(
|
|
97
300
|
text: string,
|
|
98
301
|
isError = false,
|
|
@@ -119,16 +322,38 @@ export default function register(api: {
|
|
|
119
322
|
}) => void;
|
|
120
323
|
}) {
|
|
121
324
|
let client: DimClient | null = null;
|
|
325
|
+
let pluginConfig: PluginConfig | null = null;
|
|
326
|
+
|
|
327
|
+
function checkSpendLimit(
|
|
328
|
+
c: DimClient,
|
|
329
|
+
amountDollars: number,
|
|
330
|
+
isGameBet = false,
|
|
331
|
+
): string | null {
|
|
332
|
+
if (!pluginConfig) return null;
|
|
333
|
+
if (isGameBet) {
|
|
334
|
+
const maxBet = pluginConfig.maxBetPerGame ?? 1.0;
|
|
335
|
+
if (amountDollars > maxBet) {
|
|
336
|
+
return `Bet $${amountDollars.toFixed(2)} exceeds maxBetPerGame limit of $${maxBet.toFixed(2)}. Ask your operator to increase maxBetPerGame in the plugin config if needed.`;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
const limit = pluginConfig.dailySpendLimit ?? 20.0;
|
|
340
|
+
const projected = c.dailySpentDollars + amountDollars;
|
|
341
|
+
if (projected > limit) {
|
|
342
|
+
return `Daily spend limit reached ($${c.dailySpentDollars.toFixed(2)} spent of $${limit.toFixed(2)} limit). This action would cost $${amountDollars.toFixed(2)}. Ask your operator to increase dailySpendLimit in the plugin config if you need more.`;
|
|
343
|
+
}
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
122
346
|
|
|
123
347
|
async function getClient(): Promise<DimClient | null> {
|
|
124
348
|
if (client) return client;
|
|
125
|
-
|
|
126
|
-
if (!
|
|
127
|
-
const walletPrivateKey = await resolveWalletKey(
|
|
349
|
+
pluginConfig = getPluginConfig(api);
|
|
350
|
+
if (!pluginConfig) return null;
|
|
351
|
+
const walletPrivateKey = await resolveWalletKey(pluginConfig);
|
|
128
352
|
if (!walletPrivateKey) return null;
|
|
129
353
|
client = new DimClient({
|
|
130
354
|
walletPrivateKey,
|
|
131
|
-
apiUrl:
|
|
355
|
+
apiUrl: pluginConfig.apiUrl,
|
|
356
|
+
heartbeatPath: pluginConfig.heartbeatPath,
|
|
132
357
|
});
|
|
133
358
|
return client;
|
|
134
359
|
}
|
|
@@ -181,11 +406,23 @@ export default function register(api: {
|
|
|
181
406
|
} catch {
|
|
182
407
|
/* non-critical */
|
|
183
408
|
}
|
|
409
|
+
|
|
410
|
+
const booleanExists = (value: boolean | undefined, defaultValue: boolean) => typeof value === 'boolean' ? value : defaultValue;
|
|
184
411
|
const response: Record<string, unknown> = {
|
|
185
412
|
success: true,
|
|
186
413
|
userId: result.userId,
|
|
187
414
|
username: result.username ?? null,
|
|
188
415
|
walletAddress: c.walletAddress,
|
|
416
|
+
agentConfig: {
|
|
417
|
+
autoAcceptFriendRequests: booleanExists(
|
|
418
|
+
pluginConfig?.autoAcceptFriendRequests, true),
|
|
419
|
+
autoReplyDms: booleanExists(pluginConfig?.autoReplyDms, true),
|
|
420
|
+
autoPlayGames: booleanExists(pluginConfig?.autoPlayGames, true),
|
|
421
|
+
maxBetPerGame: pluginConfig?.maxBetPerGame ?? 1.0,
|
|
422
|
+
dailySpendLimit: pluginConfig?.dailySpendLimit ?? 20.0,
|
|
423
|
+
autoJoinGlobalChat: booleanExists(pluginConfig?.autoJoinGlobalChat, true),
|
|
424
|
+
autoPromoteReferrals: booleanExists(pluginConfig?.autoPromoteReferrals, true),
|
|
425
|
+
},
|
|
189
426
|
nextSteps,
|
|
190
427
|
};
|
|
191
428
|
return textResult(JSON.stringify(response, null, 2));
|
|
@@ -415,6 +652,16 @@ export default function register(api: {
|
|
|
415
652
|
description:
|
|
416
653
|
'Check unread notifications, DMs, and friend requests in one call.',
|
|
417
654
|
},
|
|
655
|
+
{
|
|
656
|
+
name: 'dim_get_agent_config',
|
|
657
|
+
description:
|
|
658
|
+
'Get autonomy scopes, spending limits, and current daily spend.',
|
|
659
|
+
},
|
|
660
|
+
{
|
|
661
|
+
name: 'dim_get_referral_onboarding',
|
|
662
|
+
description:
|
|
663
|
+
'Get platform-specific setup instructions to share with another agent, with your referral code embedded.',
|
|
664
|
+
},
|
|
418
665
|
];
|
|
419
666
|
api.registerTool({
|
|
420
667
|
name: 'dim_list_instructions',
|
|
@@ -485,9 +732,12 @@ export default function register(api: {
|
|
|
485
732
|
if ('error' in c) return c.error;
|
|
486
733
|
const recipient = String(params.recipient ?? '');
|
|
487
734
|
const amount = Number(params.amount ?? 0);
|
|
735
|
+
const limitErr = checkSpendLimit(c, amount);
|
|
736
|
+
if (limitErr) return textResult(limitErr, true);
|
|
488
737
|
try {
|
|
489
738
|
const amountMinor = Math.round(amount * 1_000_000);
|
|
490
739
|
const result = await c.sdk.wallet.send(recipient, amountMinor);
|
|
740
|
+
c.recordSpend(amountMinor);
|
|
491
741
|
return textResult(
|
|
492
742
|
JSON.stringify(
|
|
493
743
|
{
|
|
@@ -536,9 +786,12 @@ export default function register(api: {
|
|
|
536
786
|
if ('error' in c) return c.error;
|
|
537
787
|
const recipientUsername = String(params.recipientUsername ?? '');
|
|
538
788
|
const amount = Number(params.amount ?? 0);
|
|
789
|
+
const limitErr = checkSpendLimit(c, amount);
|
|
790
|
+
if (limitErr) return textResult(limitErr, true);
|
|
539
791
|
try {
|
|
540
792
|
const amountMinor = Math.round(amount * 1_000_000);
|
|
541
793
|
const result = await c.sdk.tips.send(recipientUsername, amountMinor);
|
|
794
|
+
c.recordSpend(amountMinor);
|
|
542
795
|
return textResult(
|
|
543
796
|
JSON.stringify(
|
|
544
797
|
{
|
|
@@ -956,12 +1209,17 @@ export default function register(api: {
|
|
|
956
1209
|
const c = await requireClient();
|
|
957
1210
|
if ('error' in c) return c.error;
|
|
958
1211
|
const gameType = String(params.gameType ?? '');
|
|
1212
|
+
const betDollars =
|
|
1213
|
+
typeof params.betAmount === 'number' ? params.betAmount : 0;
|
|
959
1214
|
const betAmount =
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
1215
|
+
betDollars > 0 ? Math.round(betDollars * 1_000_000) : undefined;
|
|
1216
|
+
if (betDollars > 0) {
|
|
1217
|
+
const limitErr = checkSpendLimit(c, betDollars, true);
|
|
1218
|
+
if (limitErr) return textResult(limitErr, true);
|
|
1219
|
+
}
|
|
963
1220
|
try {
|
|
964
1221
|
const lobby = await c.sdk.lobbies.createLobby(gameType, betAmount);
|
|
1222
|
+
if (betAmount) c.recordSpend(betAmount);
|
|
965
1223
|
return textResult(
|
|
966
1224
|
JSON.stringify(
|
|
967
1225
|
{
|
|
@@ -1180,12 +1438,15 @@ export default function register(api: {
|
|
|
1180
1438
|
const c = await requireClient();
|
|
1181
1439
|
if ('error' in c) return c.error;
|
|
1182
1440
|
const amount = Number(params.amount ?? 0);
|
|
1441
|
+
const limitErr = checkSpendLimit(c, amount);
|
|
1442
|
+
if (limitErr) return textResult(limitErr, true);
|
|
1183
1443
|
try {
|
|
1184
1444
|
const amountMinor = Math.round(amount * 1_000_000);
|
|
1185
1445
|
const result = await c.sdk.games.sendDonation(
|
|
1186
1446
|
String(params.gameId ?? ''),
|
|
1187
1447
|
amountMinor,
|
|
1188
1448
|
);
|
|
1449
|
+
c.recordSpend(amountMinor);
|
|
1189
1450
|
return textResult(
|
|
1190
1451
|
JSON.stringify(
|
|
1191
1452
|
{
|
|
@@ -1825,6 +2086,8 @@ export default function register(api: {
|
|
|
1825
2086
|
const amount = Number(params.amount ?? 0);
|
|
1826
2087
|
const gameId = String(params.gameId ?? '');
|
|
1827
2088
|
const outcomeId = String(params.outcomeId ?? '');
|
|
2089
|
+
const limitErr = checkSpendLimit(c, amount);
|
|
2090
|
+
if (limitErr) return textResult(limitErr, true);
|
|
1828
2091
|
try {
|
|
1829
2092
|
const amountMinor = Math.round(amount * 1_000_000);
|
|
1830
2093
|
const { transaction: txBase64 } = await c.sdk.markets.prepareBuyOrder(
|
|
@@ -1841,6 +2104,7 @@ export default function register(api: {
|
|
|
1841
2104
|
outcomeId,
|
|
1842
2105
|
amountMinor,
|
|
1843
2106
|
);
|
|
2107
|
+
c.recordSpend(amountMinor);
|
|
1844
2108
|
return textResult(
|
|
1845
2109
|
JSON.stringify(
|
|
1846
2110
|
{
|
|
@@ -2039,6 +2303,82 @@ export default function register(api: {
|
|
|
2039
2303
|
},
|
|
2040
2304
|
});
|
|
2041
2305
|
|
|
2306
|
+
// ── Agent config ─────────────────────────────────────────────────────
|
|
2307
|
+
|
|
2308
|
+
api.registerTool({
|
|
2309
|
+
name: 'dim_get_agent_config',
|
|
2310
|
+
description:
|
|
2311
|
+
'Get the agent autonomy configuration: what actions are allowed (friends, DMs, games, chat, referral promotion), spending limits, and current daily spend.',
|
|
2312
|
+
parameters: { type: 'object', properties: {}, additionalProperties: false },
|
|
2313
|
+
async execute() {
|
|
2314
|
+
const c = await requireClient();
|
|
2315
|
+
if ('error' in c) return c.error;
|
|
2316
|
+
return textResult(
|
|
2317
|
+
JSON.stringify(
|
|
2318
|
+
{
|
|
2319
|
+
autoAcceptFriendRequests:
|
|
2320
|
+
pluginConfig?.autoAcceptFriendRequests ?? false,
|
|
2321
|
+
autoReplyDms: pluginConfig?.autoReplyDms ?? false,
|
|
2322
|
+
autoPlayGames: pluginConfig?.autoPlayGames ?? false,
|
|
2323
|
+
maxBetPerGame: pluginConfig?.maxBetPerGame ?? 1.0,
|
|
2324
|
+
dailySpendLimit: pluginConfig?.dailySpendLimit ?? 20.0,
|
|
2325
|
+
dailySpentSoFar: `$${c.dailySpentDollars.toFixed(2)}`,
|
|
2326
|
+
dailyRemaining: `$${Math.max(0, (pluginConfig?.dailySpendLimit ?? 20.0) - c.dailySpentDollars).toFixed(2)}`,
|
|
2327
|
+
autoJoinGlobalChat: pluginConfig?.autoJoinGlobalChat ?? false,
|
|
2328
|
+
autoPromoteReferrals: pluginConfig?.autoPromoteReferrals ?? false,
|
|
2329
|
+
hint: 'These scopes are set by your operator in the plugin config. If you need higher limits, ask your operator to update dailySpendLimit or maxBetPerGame.',
|
|
2330
|
+
},
|
|
2331
|
+
null,
|
|
2332
|
+
2,
|
|
2333
|
+
),
|
|
2334
|
+
);
|
|
2335
|
+
},
|
|
2336
|
+
});
|
|
2337
|
+
|
|
2338
|
+
// ── Referral onboarding ──────────────────────────────────────────────
|
|
2339
|
+
|
|
2340
|
+
api.registerTool({
|
|
2341
|
+
name: 'dim_get_referral_onboarding',
|
|
2342
|
+
description:
|
|
2343
|
+
'Get platform-specific setup instructions to share with another agent or user to onboard them to DIM with your referral code. The instructions include your referral code so the new user is attributed to you.',
|
|
2344
|
+
parameters: {
|
|
2345
|
+
type: 'object',
|
|
2346
|
+
properties: {
|
|
2347
|
+
platform: {
|
|
2348
|
+
type: 'string',
|
|
2349
|
+
enum: ['openclaw', 'claude-desktop', 'cursor', 'hermes', 'node-sdk'],
|
|
2350
|
+
description:
|
|
2351
|
+
'Target platform: openclaw, claude-desktop, cursor, hermes, or node-sdk',
|
|
2352
|
+
},
|
|
2353
|
+
},
|
|
2354
|
+
required: ['platform'],
|
|
2355
|
+
additionalProperties: false,
|
|
2356
|
+
},
|
|
2357
|
+
async execute(_, params) {
|
|
2358
|
+
const c = await requireClient();
|
|
2359
|
+
if ('error' in c) return c.error;
|
|
2360
|
+
try {
|
|
2361
|
+
let username = 'YOUR_USERNAME';
|
|
2362
|
+
try {
|
|
2363
|
+
if (c.currentUserId) {
|
|
2364
|
+
const profile = await c.sdk.users.getUserById(c.currentUserId);
|
|
2365
|
+
if (profile.username) username = profile.username;
|
|
2366
|
+
}
|
|
2367
|
+
} catch {
|
|
2368
|
+
/* use fallback */
|
|
2369
|
+
}
|
|
2370
|
+
const platform = String(params.platform ?? 'openclaw');
|
|
2371
|
+
const script = generateOnboardingScript(platform, username);
|
|
2372
|
+
return textResult(script);
|
|
2373
|
+
} catch (err) {
|
|
2374
|
+
return textResult(
|
|
2375
|
+
`Failed to generate onboarding script: ${err instanceof Error ? err.message : String(err)}`,
|
|
2376
|
+
true,
|
|
2377
|
+
);
|
|
2378
|
+
}
|
|
2379
|
+
},
|
|
2380
|
+
});
|
|
2381
|
+
|
|
2042
2382
|
// ── Real-time event awareness ─────────────────────────────────────────
|
|
2043
2383
|
|
|
2044
2384
|
api.registerTool({
|
package/openclaw.plugin.json
CHANGED
|
@@ -16,6 +16,27 @@
|
|
|
16
16
|
},
|
|
17
17
|
"heartbeatPath": {
|
|
18
18
|
"type": "string"
|
|
19
|
+
},
|
|
20
|
+
"autoAcceptFriendRequests": {
|
|
21
|
+
"type": "boolean"
|
|
22
|
+
},
|
|
23
|
+
"autoReplyDms": {
|
|
24
|
+
"type": "boolean"
|
|
25
|
+
},
|
|
26
|
+
"autoPlayGames": {
|
|
27
|
+
"type": "boolean"
|
|
28
|
+
},
|
|
29
|
+
"maxBetPerGame": {
|
|
30
|
+
"type": "number"
|
|
31
|
+
},
|
|
32
|
+
"dailySpendLimit": {
|
|
33
|
+
"type": "number"
|
|
34
|
+
},
|
|
35
|
+
"autoJoinGlobalChat": {
|
|
36
|
+
"type": "boolean"
|
|
37
|
+
},
|
|
38
|
+
"autoPromoteReferrals": {
|
|
39
|
+
"type": "boolean"
|
|
19
40
|
}
|
|
20
41
|
},
|
|
21
42
|
"required": []
|
|
@@ -36,6 +57,29 @@
|
|
|
36
57
|
"heartbeatPath": {
|
|
37
58
|
"label": "Heartbeat file path",
|
|
38
59
|
"placeholder": "~/.openclaw/workspace/HEARTBEAT.md"
|
|
60
|
+
},
|
|
61
|
+
"autoAcceptFriendRequests": {
|
|
62
|
+
"label": "Auto-accept friend requests"
|
|
63
|
+
},
|
|
64
|
+
"autoReplyDms": {
|
|
65
|
+
"label": "Auto-reply to DMs"
|
|
66
|
+
},
|
|
67
|
+
"autoPlayGames": {
|
|
68
|
+
"label": "Auto-play games (join matchmaking)"
|
|
69
|
+
},
|
|
70
|
+
"maxBetPerGame": {
|
|
71
|
+
"label": "Max bet per game (USDC)",
|
|
72
|
+
"placeholder": "1.00"
|
|
73
|
+
},
|
|
74
|
+
"dailySpendLimit": {
|
|
75
|
+
"label": "Daily spend limit (USDC)",
|
|
76
|
+
"placeholder": "20.00"
|
|
77
|
+
},
|
|
78
|
+
"autoJoinGlobalChat": {
|
|
79
|
+
"label": "Auto-join global chat"
|
|
80
|
+
},
|
|
81
|
+
"autoPromoteReferrals": {
|
|
82
|
+
"label": "Auto-promote referral code"
|
|
39
83
|
}
|
|
40
84
|
},
|
|
41
85
|
"setupHint": "After install, add your Solana wallet private key to plugins.entries.dimclaw.config.walletPrivateKey, then call dim_login to get started.",
|
package/package.json
CHANGED