@framers/agentos-ext-wallet 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/manifest.json +2 -2
- package/package.json +12 -9
- package/src/AgentWalletManager.ts +0 -324
- package/src/SpendingPolicyEnforcer.ts +0 -169
- package/src/cards/CardManager.ts +0 -274
- package/src/cards/LithicCardAdapter.ts +0 -159
- package/src/cards/MccCategoryMap.ts +0 -138
- package/src/cards/types.ts +0 -169
- package/src/chains/EvmWalletAdapter.ts +0 -170
- package/src/chains/SolanaWalletAdapter.ts +0 -184
- package/src/index.ts +0 -315
- package/src/tools/CardSpendingSummaryTool.ts +0 -52
- package/src/tools/CardStatusTool.ts +0 -68
- package/src/tools/CheckBalanceTool.ts +0 -145
- package/src/tools/FreezeCardTool.ts +0 -52
- package/src/tools/IssueCardTool.ts +0 -76
- package/src/tools/PayWithCardTool.ts +0 -109
- package/src/tools/SendCryptoTool.ts +0 -185
- package/src/tools/UnfreezeCardTool.ts +0 -52
- package/src/tools/WalletHistoryTool.ts +0 -113
- package/src/types.ts +0 -230
- package/test/AgentWalletManager.spec.ts +0 -301
- package/test/CardManager.spec.ts +0 -428
- package/test/LithicCardAdapter.spec.ts +0 -224
- package/test/MccCategoryMap.spec.ts +0 -153
- package/test/SpendingPolicyEnforcer.spec.ts +0 -254
- package/test/card-integration.spec.ts +0 -242
- package/test/card-tools.spec.ts +0 -285
- package/test/integration.spec.ts +0 -171
- package/test/wallet-tools.spec.ts +0 -275
- package/tsconfig.json +0 -22
package/src/index.ts
DELETED
|
@@ -1,315 +0,0 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
/**
|
|
3
|
-
* @fileoverview Agent Personal Wallet Extension Pack.
|
|
4
|
-
*
|
|
5
|
-
* Provides autonomous crypto spending tools with configurable guardrails:
|
|
6
|
-
* - check_wallet_balance — query balances across Solana/EVM chains
|
|
7
|
-
* - send_crypto — send with spending policy enforcement
|
|
8
|
-
* - wallet_transaction_history — view recent transactions
|
|
9
|
-
*
|
|
10
|
-
* @module @framers/agentos-ext-wallet
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import { AgentWalletManager } from './AgentWalletManager.js';
|
|
14
|
-
import { SpendingPolicyEnforcer } from './SpendingPolicyEnforcer.js';
|
|
15
|
-
import { SolanaWalletAdapter } from './chains/SolanaWalletAdapter.js';
|
|
16
|
-
import { EvmWalletAdapter } from './chains/EvmWalletAdapter.js';
|
|
17
|
-
import { createCheckBalanceTool } from './tools/CheckBalanceTool.js';
|
|
18
|
-
import { createSendCryptoTool } from './tools/SendCryptoTool.js';
|
|
19
|
-
import { createWalletHistoryTool } from './tools/WalletHistoryTool.js';
|
|
20
|
-
import { createIssueCardTool } from './tools/IssueCardTool.js';
|
|
21
|
-
import { createCardStatusTool } from './tools/CardStatusTool.js';
|
|
22
|
-
import { createFreezeCardTool } from './tools/FreezeCardTool.js';
|
|
23
|
-
import { createUnfreezeCardTool } from './tools/UnfreezeCardTool.js';
|
|
24
|
-
import { createCardSpendingSummaryTool } from './tools/CardSpendingSummaryTool.js';
|
|
25
|
-
import { createPayWithCardTool } from './tools/PayWithCardTool.js';
|
|
26
|
-
import { CardManager } from './cards/CardManager.js';
|
|
27
|
-
import { LithicCardAdapter } from './cards/LithicCardAdapter.js';
|
|
28
|
-
import { MccCategoryMap } from './cards/MccCategoryMap.js';
|
|
29
|
-
import { DEFAULT_SPENDING_POLICY } from './types.js';
|
|
30
|
-
import type { ChainId, WalletConfig } from './types.js';
|
|
31
|
-
import type { CardConfig, ICardStore, AgentCardRecord, CardTransactionRecord, CardState, CardTxStatus } from './cards/types.js';
|
|
32
|
-
|
|
33
|
-
/* ------------------------------------------------------------------ */
|
|
34
|
-
/* Extension pack types */
|
|
35
|
-
/* ------------------------------------------------------------------ */
|
|
36
|
-
|
|
37
|
-
export interface ExtensionContext {
|
|
38
|
-
options?: Record<string, unknown>;
|
|
39
|
-
secrets?: Record<string, string>;
|
|
40
|
-
getSecret?: (key: string) => string | undefined;
|
|
41
|
-
logger?: { info: (msg: string) => void; warn?: (msg: string) => void };
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface ExtensionPack {
|
|
45
|
-
name: string;
|
|
46
|
-
version: string;
|
|
47
|
-
descriptors: Array<{
|
|
48
|
-
id: string;
|
|
49
|
-
kind: string;
|
|
50
|
-
priority?: number;
|
|
51
|
-
payload: unknown;
|
|
52
|
-
}>;
|
|
53
|
-
onActivate?: () => Promise<void>;
|
|
54
|
-
onDeactivate?: () => Promise<void>;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/* ------------------------------------------------------------------ */
|
|
58
|
-
/* In-memory stores (CLI/ephemeral — production would use DB) */
|
|
59
|
-
/* ------------------------------------------------------------------ */
|
|
60
|
-
|
|
61
|
-
function createMemoryLedgerStore() {
|
|
62
|
-
const data: Array<{ agentId: string; category: string; amountUsd: number; periodKey: string }> = [];
|
|
63
|
-
return {
|
|
64
|
-
async sumByPeriod(agentId: string, periodKey: string) {
|
|
65
|
-
return data.filter(e => e.agentId === agentId && e.periodKey === periodKey)
|
|
66
|
-
.reduce((sum, e) => sum + e.amountUsd, 0);
|
|
67
|
-
},
|
|
68
|
-
async sumByCategoryAndPeriod(agentId: string, category: string, periodKey: string) {
|
|
69
|
-
return data.filter(e => e.agentId === agentId && e.category === category && e.periodKey === periodKey)
|
|
70
|
-
.reduce((sum, e) => sum + e.amountUsd, 0);
|
|
71
|
-
},
|
|
72
|
-
async insert(entry: any) { data.push(entry); },
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function createMemoryWalletStore() {
|
|
77
|
-
const walletRecords = new Map<string, any>();
|
|
78
|
-
const txRecords = new Map<string, any[]>();
|
|
79
|
-
return {
|
|
80
|
-
async getWallet(agentId: string, chain: string) {
|
|
81
|
-
return walletRecords.get(`${agentId}:${chain}`) || null;
|
|
82
|
-
},
|
|
83
|
-
async getAllWallets(agentId: string) {
|
|
84
|
-
return [...walletRecords.values()].filter((w: any) => w.agentId === agentId);
|
|
85
|
-
},
|
|
86
|
-
async saveWallet(record: any) {
|
|
87
|
-
walletRecords.set(`${record.agentId}:${record.chain}`, record);
|
|
88
|
-
},
|
|
89
|
-
async insertTransaction(record: any) {
|
|
90
|
-
const list = txRecords.get(record.walletId) || [];
|
|
91
|
-
list.push(record);
|
|
92
|
-
txRecords.set(record.walletId, list);
|
|
93
|
-
},
|
|
94
|
-
async updateTransactionStatus(id: string, status: string, txHash?: string) {
|
|
95
|
-
for (const [, list] of txRecords) {
|
|
96
|
-
const tx = list.find((t: any) => t.id === id);
|
|
97
|
-
if (tx) { tx.status = status; if (txHash) tx.txHash = txHash; return; }
|
|
98
|
-
}
|
|
99
|
-
},
|
|
100
|
-
async getTransactions(walletId: string, limit = 20) {
|
|
101
|
-
return (txRecords.get(walletId) || []).slice(-limit).reverse();
|
|
102
|
-
},
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function createMemoryCardStore(): ICardStore {
|
|
107
|
-
const cards = new Map<string, AgentCardRecord>();
|
|
108
|
-
const txRecords = new Map<string, CardTransactionRecord[]>();
|
|
109
|
-
return {
|
|
110
|
-
async getCard(agentId: string) {
|
|
111
|
-
return [...cards.values()].find(c => c.agentId === agentId) || null;
|
|
112
|
-
},
|
|
113
|
-
async saveCard(record: AgentCardRecord) {
|
|
114
|
-
cards.set(record.id, record);
|
|
115
|
-
},
|
|
116
|
-
async updateCardState(agentId: string, state: CardState) {
|
|
117
|
-
for (const card of cards.values()) {
|
|
118
|
-
if (card.agentId === agentId) { card.state = state; return; }
|
|
119
|
-
}
|
|
120
|
-
},
|
|
121
|
-
async insertTransaction(record: CardTransactionRecord) {
|
|
122
|
-
const list = txRecords.get(record.cardId) || [];
|
|
123
|
-
list.push(record);
|
|
124
|
-
txRecords.set(record.cardId, list);
|
|
125
|
-
},
|
|
126
|
-
async updateTransactionStatus(id: string, status: CardTxStatus) {
|
|
127
|
-
for (const [, list] of txRecords) {
|
|
128
|
-
const tx = list.find(t => t.id === id);
|
|
129
|
-
if (tx) { tx.status = status; return; }
|
|
130
|
-
}
|
|
131
|
-
},
|
|
132
|
-
async getTransactions(cardId: string, limit = 20) {
|
|
133
|
-
return (txRecords.get(cardId) || []).slice(-limit).reverse();
|
|
134
|
-
},
|
|
135
|
-
async getTransactionsByPeriod(cardId: string, since: number) {
|
|
136
|
-
return (txRecords.get(cardId) || []).filter(t => t.createdAt >= since);
|
|
137
|
-
},
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/* ------------------------------------------------------------------ */
|
|
142
|
-
/* Factory */
|
|
143
|
-
/* ------------------------------------------------------------------ */
|
|
144
|
-
|
|
145
|
-
export function createExtensionPack(context: ExtensionContext): ExtensionPack {
|
|
146
|
-
const opts = (context.options || {}) as Partial<WalletConfig>;
|
|
147
|
-
const walletConfig: WalletConfig = {
|
|
148
|
-
enabled: opts.enabled ?? true,
|
|
149
|
-
chains: opts.chains || ['solana'],
|
|
150
|
-
custodyMode: opts.custodyMode || 'encrypted-hot',
|
|
151
|
-
allowedTokens: opts.allowedTokens || ['SOL', 'USDC'],
|
|
152
|
-
spendingPolicy: opts.spendingPolicy || DEFAULT_SPENDING_POLICY,
|
|
153
|
-
card: (opts as any).card,
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
// Build chain adapters
|
|
157
|
-
const adapters = new Map<ChainId, any>();
|
|
158
|
-
for (const chain of walletConfig.chains) {
|
|
159
|
-
if (chain === 'solana') adapters.set('solana', new SolanaWalletAdapter());
|
|
160
|
-
else adapters.set(chain, new EvmWalletAdapter({ chain }));
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const masterSecret =
|
|
164
|
-
context.getSecret?.('WALLET_MASTER_SECRET')
|
|
165
|
-
|| context.secrets?.['WALLET_MASTER_SECRET']
|
|
166
|
-
|| process.env['WALLET_MASTER_SECRET']
|
|
167
|
-
|| 'dev-secret-change-me';
|
|
168
|
-
|
|
169
|
-
const policyEnforcer = new SpendingPolicyEnforcer(walletConfig.spendingPolicy, createMemoryLedgerStore());
|
|
170
|
-
|
|
171
|
-
const walletManager = new AgentWalletManager({
|
|
172
|
-
masterSecret,
|
|
173
|
-
walletConfig,
|
|
174
|
-
store: createMemoryWalletStore(),
|
|
175
|
-
policyEnforcer,
|
|
176
|
-
adapters,
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
const checkBalance = createCheckBalanceTool(walletManager);
|
|
180
|
-
const sendCrypto = createSendCryptoTool(walletManager);
|
|
181
|
-
const walletHistory = createWalletHistoryTool(walletManager);
|
|
182
|
-
|
|
183
|
-
const descriptors: ExtensionPack['descriptors'] = [
|
|
184
|
-
{ id: checkBalance.name, kind: 'tool' as const, priority: 50, payload: checkBalance },
|
|
185
|
-
{ id: sendCrypto.name, kind: 'tool' as const, priority: 50, payload: sendCrypto },
|
|
186
|
-
{ id: walletHistory.name, kind: 'tool' as const, priority: 50, payload: walletHistory },
|
|
187
|
-
];
|
|
188
|
-
|
|
189
|
-
// Card tools (Lithic) — only if card config is enabled
|
|
190
|
-
let cardManager: CardManager | undefined;
|
|
191
|
-
const cardConfig = walletConfig.card;
|
|
192
|
-
if (cardConfig?.enabled) {
|
|
193
|
-
const lithicApiKey =
|
|
194
|
-
context.getSecret?.('LITHIC_API_KEY')
|
|
195
|
-
|| context.secrets?.['LITHIC_API_KEY']
|
|
196
|
-
|| process.env['LITHIC_API_KEY']
|
|
197
|
-
|| '';
|
|
198
|
-
|
|
199
|
-
const lithicAdapter = new LithicCardAdapter({
|
|
200
|
-
apiKey: lithicApiKey,
|
|
201
|
-
sandbox: process.env['NODE_ENV'] !== 'production',
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
const mccMap = new MccCategoryMap();
|
|
205
|
-
|
|
206
|
-
cardManager = new CardManager({
|
|
207
|
-
adapter: lithicAdapter,
|
|
208
|
-
store: createMemoryCardStore(),
|
|
209
|
-
policyEnforcer,
|
|
210
|
-
mccMap,
|
|
211
|
-
config: cardConfig,
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
const issueCard = createIssueCardTool(cardManager);
|
|
215
|
-
const cardStatus = createCardStatusTool(cardManager);
|
|
216
|
-
const freezeCard = createFreezeCardTool(cardManager);
|
|
217
|
-
const unfreezeCard = createUnfreezeCardTool(cardManager);
|
|
218
|
-
const cardSpending = createCardSpendingSummaryTool(cardManager);
|
|
219
|
-
const payWithCard = createPayWithCardTool(cardManager);
|
|
220
|
-
|
|
221
|
-
descriptors.push(
|
|
222
|
-
{ id: issueCard.name, kind: 'tool' as const, priority: 50, payload: issueCard },
|
|
223
|
-
{ id: cardStatus.name, kind: 'tool' as const, priority: 50, payload: cardStatus },
|
|
224
|
-
{ id: freezeCard.name, kind: 'tool' as const, priority: 50, payload: freezeCard },
|
|
225
|
-
{ id: unfreezeCard.name, kind: 'tool' as const, priority: 50, payload: unfreezeCard },
|
|
226
|
-
{ id: cardSpending.name, kind: 'tool' as const, priority: 50, payload: cardSpending },
|
|
227
|
-
{ id: payWithCard.name, kind: 'tool' as const, priority: 50, payload: payWithCard },
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const features: string[] = [`chains: ${walletConfig.chains.join(', ')}`];
|
|
232
|
-
if (cardConfig?.enabled) features.push('virtual card (Lithic)');
|
|
233
|
-
|
|
234
|
-
return {
|
|
235
|
-
name: '@framers/agentos-ext-wallet',
|
|
236
|
-
version: '0.2.0',
|
|
237
|
-
descriptors,
|
|
238
|
-
onActivate: async () => context.logger?.info(`Wallet extension activated (${features.join(', ')})`),
|
|
239
|
-
onDeactivate: async () => context.logger?.info('Wallet extension deactivated'),
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/* ------------------------------------------------------------------ */
|
|
244
|
-
/* Re-exports */
|
|
245
|
-
/* ------------------------------------------------------------------ */
|
|
246
|
-
|
|
247
|
-
// Core
|
|
248
|
-
export { AgentWalletManager, ApprovalRequiredError, SpendingPolicyViolation } from './AgentWalletManager.js';
|
|
249
|
-
export type { AgentWalletManagerOptions, IWalletStore } from './AgentWalletManager.js';
|
|
250
|
-
export { SpendingPolicyEnforcer } from './SpendingPolicyEnforcer.js';
|
|
251
|
-
export type { ISpendingLedgerStore } from './SpendingPolicyEnforcer.js';
|
|
252
|
-
|
|
253
|
-
// Types
|
|
254
|
-
export type {
|
|
255
|
-
AgentWalletRecord,
|
|
256
|
-
CategoryBudget,
|
|
257
|
-
ChainId,
|
|
258
|
-
IChainWalletAdapter,
|
|
259
|
-
SpendCategory,
|
|
260
|
-
SpendCheckResult,
|
|
261
|
-
SpendingLedgerEntry,
|
|
262
|
-
SpendingPolicyConfig,
|
|
263
|
-
TokenInfo,
|
|
264
|
-
TokenSymbol,
|
|
265
|
-
WalletConfig,
|
|
266
|
-
WalletDirection,
|
|
267
|
-
WalletTransactionRecord,
|
|
268
|
-
WalletTxStatus,
|
|
269
|
-
} from './types.js';
|
|
270
|
-
export { DEFAULT_SPENDING_POLICY, DEFAULT_WALLET_CONFIG } from './types.js';
|
|
271
|
-
|
|
272
|
-
// Chain adapters
|
|
273
|
-
export { SolanaWalletAdapter } from './chains/SolanaWalletAdapter.js';
|
|
274
|
-
export type { SolanaWalletAdapterOptions } from './chains/SolanaWalletAdapter.js';
|
|
275
|
-
export { EvmWalletAdapter, KNOWN_TOKENS } from './chains/EvmWalletAdapter.js';
|
|
276
|
-
export type { EvmWalletAdapterOptions } from './chains/EvmWalletAdapter.js';
|
|
277
|
-
|
|
278
|
-
// Tool factories — crypto
|
|
279
|
-
export { createCheckBalanceTool } from './tools/CheckBalanceTool.js';
|
|
280
|
-
export { createSendCryptoTool } from './tools/SendCryptoTool.js';
|
|
281
|
-
export { createWalletHistoryTool } from './tools/WalletHistoryTool.js';
|
|
282
|
-
|
|
283
|
-
// Tool factories — card
|
|
284
|
-
export { createIssueCardTool } from './tools/IssueCardTool.js';
|
|
285
|
-
export { createCardStatusTool } from './tools/CardStatusTool.js';
|
|
286
|
-
export { createFreezeCardTool } from './tools/FreezeCardTool.js';
|
|
287
|
-
export { createUnfreezeCardTool } from './tools/UnfreezeCardTool.js';
|
|
288
|
-
export { createCardSpendingSummaryTool } from './tools/CardSpendingSummaryTool.js';
|
|
289
|
-
export { createPayWithCardTool } from './tools/PayWithCardTool.js';
|
|
290
|
-
|
|
291
|
-
// Card subsystem
|
|
292
|
-
export { CardManager } from './cards/CardManager.js';
|
|
293
|
-
export type { CardManagerOptions } from './cards/CardManager.js';
|
|
294
|
-
export { CardSpendingBlockedError } from './cards/CardManager.js';
|
|
295
|
-
export { LithicCardAdapter, LithicApiError } from './cards/LithicCardAdapter.js';
|
|
296
|
-
export type { LithicCardAdapterOptions } from './cards/LithicCardAdapter.js';
|
|
297
|
-
export { MccCategoryMap } from './cards/MccCategoryMap.js';
|
|
298
|
-
export type {
|
|
299
|
-
AgentCardRecord,
|
|
300
|
-
CardConfig,
|
|
301
|
-
CardTransactionRecord,
|
|
302
|
-
CardTxStatus,
|
|
303
|
-
CardState,
|
|
304
|
-
CardType,
|
|
305
|
-
CardNetwork,
|
|
306
|
-
ICardAdapter,
|
|
307
|
-
ICardStore,
|
|
308
|
-
LithicCardResponse,
|
|
309
|
-
LithicTransaction,
|
|
310
|
-
SpendingSummary,
|
|
311
|
-
SpendLimitDuration,
|
|
312
|
-
} from './cards/types.js';
|
|
313
|
-
export { DEFAULT_CARD_CONFIG } from './cards/types.js';
|
|
314
|
-
|
|
315
|
-
export default createExtensionPack;
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
/**
|
|
3
|
-
* @fileoverview Agent-callable tool for card spending breakdown.
|
|
4
|
-
* @module wallet/tools/CardSpendingSummaryTool
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { ITool, ToolExecutionContext, ToolExecutionResult } from '@framers/agentos/core/tools/ITool';
|
|
8
|
-
import type { CardManager } from '../cards/CardManager.js';
|
|
9
|
-
import type { SpendingSummary } from '../cards/types.js';
|
|
10
|
-
|
|
11
|
-
interface SpendingSummaryInput {
|
|
12
|
-
/** Time period: 'day' or 'month'. Defaults to 'month'. */
|
|
13
|
-
period?: 'day' | 'month';
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function createCardSpendingSummaryTool(cardManager: CardManager): ITool<SpendingSummaryInput, SpendingSummary> {
|
|
17
|
-
return {
|
|
18
|
-
id: 'wallet-card-spending-summary-v1',
|
|
19
|
-
name: 'card_spending_summary',
|
|
20
|
-
displayName: 'Card Spending Summary',
|
|
21
|
-
description:
|
|
22
|
-
'Get a spending breakdown for the agent\'s virtual card, grouped by category '
|
|
23
|
-
+ '(dining, shopping, subscriptions, etc.). Shows daily or monthly totals.',
|
|
24
|
-
category: 'wallet',
|
|
25
|
-
version: '1.0.0',
|
|
26
|
-
hasSideEffects: false,
|
|
27
|
-
requiredCapabilities: ['capability:wallet', 'capability:wallet_card'],
|
|
28
|
-
|
|
29
|
-
inputSchema: {
|
|
30
|
-
type: 'object',
|
|
31
|
-
properties: {
|
|
32
|
-
period: {
|
|
33
|
-
type: 'string',
|
|
34
|
-
enum: ['day', 'month'],
|
|
35
|
-
description: 'Time period for the summary. Defaults to "month".',
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
|
|
40
|
-
async execute(args: SpendingSummaryInput, context: ToolExecutionContext): Promise<ToolExecutionResult<SpendingSummary>> {
|
|
41
|
-
try {
|
|
42
|
-
const agentId = context.gmiId;
|
|
43
|
-
const period = args.period || 'month';
|
|
44
|
-
const summary = await cardManager.getSpendingSummary(agentId, period);
|
|
45
|
-
|
|
46
|
-
return { success: true, output: summary };
|
|
47
|
-
} catch (err: any) {
|
|
48
|
-
return { success: false, error: err.message || String(err) };
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
};
|
|
52
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
/**
|
|
3
|
-
* @fileoverview Agent-callable tool for checking card status.
|
|
4
|
-
* @module wallet/tools/CardStatusTool
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { ITool, ToolExecutionContext, ToolExecutionResult } from '@framers/agentos/core/tools/ITool';
|
|
8
|
-
import type { CardManager } from '../cards/CardManager.js';
|
|
9
|
-
|
|
10
|
-
interface CardStatusInput {}
|
|
11
|
-
|
|
12
|
-
interface CardStatusOutput {
|
|
13
|
-
cardId: string;
|
|
14
|
-
last4: string;
|
|
15
|
-
state: string;
|
|
16
|
-
cardType: string;
|
|
17
|
-
spendLimitUsd: number;
|
|
18
|
-
spendLimitDuration: string;
|
|
19
|
-
network: string;
|
|
20
|
-
memo?: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function createCardStatusTool(cardManager: CardManager): ITool<CardStatusInput, CardStatusOutput> {
|
|
24
|
-
return {
|
|
25
|
-
id: 'wallet-card-status-v1',
|
|
26
|
-
name: 'card_status',
|
|
27
|
-
displayName: 'Card Status',
|
|
28
|
-
description:
|
|
29
|
-
'Get the current status of the agent\'s virtual card, including state (OPEN/PAUSED/CLOSED), '
|
|
30
|
-
+ 'spending limit, and card type.',
|
|
31
|
-
category: 'wallet',
|
|
32
|
-
version: '1.0.0',
|
|
33
|
-
hasSideEffects: false,
|
|
34
|
-
requiredCapabilities: ['capability:wallet', 'capability:wallet_card'],
|
|
35
|
-
|
|
36
|
-
inputSchema: {
|
|
37
|
-
type: 'object',
|
|
38
|
-
properties: {},
|
|
39
|
-
},
|
|
40
|
-
|
|
41
|
-
async execute(_args: CardStatusInput, context: ToolExecutionContext): Promise<ToolExecutionResult<CardStatusOutput>> {
|
|
42
|
-
try {
|
|
43
|
-
const agentId = context.gmiId;
|
|
44
|
-
const card = await cardManager.getCard(agentId);
|
|
45
|
-
|
|
46
|
-
if (!card) {
|
|
47
|
-
return { success: false, error: 'No card found. Issue one first with issue_virtual_card.' };
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return {
|
|
51
|
-
success: true,
|
|
52
|
-
output: {
|
|
53
|
-
cardId: card.id,
|
|
54
|
-
last4: card.last4,
|
|
55
|
-
state: card.state,
|
|
56
|
-
cardType: card.cardType,
|
|
57
|
-
spendLimitUsd: card.spendLimitUsd,
|
|
58
|
-
spendLimitDuration: card.spendLimitDuration,
|
|
59
|
-
network: card.network,
|
|
60
|
-
memo: card.memo,
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
} catch (err: any) {
|
|
64
|
-
return { success: false, error: err.message || String(err) };
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
};
|
|
68
|
-
}
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
/**
|
|
3
|
-
* @fileoverview Agent-callable tool for checking wallet balances.
|
|
4
|
-
* @module wunderland/wallet/tools/CheckBalanceTool
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { ITool, ToolExecutionContext, ToolExecutionResult } from '@framers/agentos/core/tools/ITool';
|
|
8
|
-
import type { AgentWalletManager } from '../AgentWalletManager.js';
|
|
9
|
-
import type { ChainId, TokenSymbol } from '../types.js';
|
|
10
|
-
|
|
11
|
-
interface CheckBalanceInput {
|
|
12
|
-
/** Chain to check. Defaults to 'solana'. */
|
|
13
|
-
chain?: ChainId;
|
|
14
|
-
/** Token symbol. If omitted, returns native token balance. */
|
|
15
|
-
token?: TokenSymbol;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface BalanceOutput {
|
|
19
|
-
chain: ChainId;
|
|
20
|
-
address: string;
|
|
21
|
-
token: string;
|
|
22
|
-
balanceRaw: string;
|
|
23
|
-
balanceFormatted: string;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/** Well-known SPL / ERC-20 mint addresses for balance lookups. */
|
|
27
|
-
const TOKEN_MINTS: Record<string, Record<string, string>> = {
|
|
28
|
-
solana: {
|
|
29
|
-
USDC: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
30
|
-
USDT: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
|
|
31
|
-
},
|
|
32
|
-
ethereum: {
|
|
33
|
-
USDC: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
34
|
-
USDT: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
|
|
35
|
-
},
|
|
36
|
-
base: {
|
|
37
|
-
USDC: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
38
|
-
USDT: '0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2',
|
|
39
|
-
},
|
|
40
|
-
polygon: {
|
|
41
|
-
USDC: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',
|
|
42
|
-
USDT: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const DECIMALS: Record<string, number> = {
|
|
47
|
-
SOL: 9,
|
|
48
|
-
ETH: 18,
|
|
49
|
-
USDC: 6,
|
|
50
|
-
USDT: 6,
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
function formatBalance(raw: bigint, decimals: number): string {
|
|
54
|
-
const str = raw.toString().padStart(decimals + 1, '0');
|
|
55
|
-
const intPart = str.slice(0, str.length - decimals) || '0';
|
|
56
|
-
const fracPart = str.slice(str.length - decimals);
|
|
57
|
-
// Trim trailing zeros but keep at least 2 decimal places
|
|
58
|
-
const trimmed = fracPart.replace(/0+$/, '').padEnd(2, '0');
|
|
59
|
-
return `${intPart}.${trimmed}`;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function createCheckBalanceTool(walletManager: AgentWalletManager): ITool<CheckBalanceInput, BalanceOutput> {
|
|
63
|
-
return {
|
|
64
|
-
id: 'wallet-check-balance-v1',
|
|
65
|
-
name: 'check_wallet_balance',
|
|
66
|
-
displayName: 'Check Wallet Balance',
|
|
67
|
-
description:
|
|
68
|
-
'Check the balance of the agent\'s personal wallet on a given blockchain. '
|
|
69
|
-
+ 'Returns the balance in both raw units and human-readable format. '
|
|
70
|
-
+ 'Supports SOL (Solana), ETH (Ethereum/Base), USDC, and USDT.',
|
|
71
|
-
category: 'wallet',
|
|
72
|
-
version: '1.0.0',
|
|
73
|
-
hasSideEffects: false,
|
|
74
|
-
requiredCapabilities: ['capability:wallet'],
|
|
75
|
-
|
|
76
|
-
inputSchema: {
|
|
77
|
-
type: 'object',
|
|
78
|
-
properties: {
|
|
79
|
-
chain: {
|
|
80
|
-
type: 'string',
|
|
81
|
-
enum: ['solana', 'ethereum', 'base', 'polygon'],
|
|
82
|
-
description: 'Blockchain to query. Defaults to solana.',
|
|
83
|
-
},
|
|
84
|
-
token: {
|
|
85
|
-
type: 'string',
|
|
86
|
-
enum: ['SOL', 'ETH', 'USDC', 'USDT'],
|
|
87
|
-
description: 'Token to check. Omit for native token (SOL/ETH).',
|
|
88
|
-
},
|
|
89
|
-
},
|
|
90
|
-
},
|
|
91
|
-
|
|
92
|
-
async execute(args: CheckBalanceInput, context: ToolExecutionContext): Promise<ToolExecutionResult<BalanceOutput>> {
|
|
93
|
-
try {
|
|
94
|
-
const chain: ChainId = args.chain || 'solana';
|
|
95
|
-
const agentId = context.gmiId;
|
|
96
|
-
|
|
97
|
-
const wallet = await walletManager.getWallet(agentId, chain);
|
|
98
|
-
if (!wallet) {
|
|
99
|
-
return {
|
|
100
|
-
success: false,
|
|
101
|
-
error: `No ${chain} wallet found. Create one first with the wallet setup.`,
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
let balanceRaw: bigint;
|
|
106
|
-
let tokenLabel: string;
|
|
107
|
-
|
|
108
|
-
const nativeToken = chain === 'solana' ? 'SOL' : 'ETH';
|
|
109
|
-
|
|
110
|
-
if (!args.token || args.token === nativeToken) {
|
|
111
|
-
// Native token balance
|
|
112
|
-
balanceRaw = await walletManager.getBalance(agentId, chain);
|
|
113
|
-
tokenLabel = nativeToken;
|
|
114
|
-
} else {
|
|
115
|
-
// Token balance
|
|
116
|
-
const mint = TOKEN_MINTS[chain]?.[args.token];
|
|
117
|
-
if (!mint) {
|
|
118
|
-
return {
|
|
119
|
-
success: false,
|
|
120
|
-
error: `Token ${args.token} is not supported on ${chain}.`,
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
balanceRaw = await walletManager.getTokenBalance(agentId, chain, mint);
|
|
124
|
-
tokenLabel = args.token;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const decimals = DECIMALS[tokenLabel] || 18;
|
|
128
|
-
const formatted = formatBalance(balanceRaw, decimals);
|
|
129
|
-
|
|
130
|
-
return {
|
|
131
|
-
success: true,
|
|
132
|
-
output: {
|
|
133
|
-
chain,
|
|
134
|
-
address: wallet.address,
|
|
135
|
-
token: tokenLabel,
|
|
136
|
-
balanceRaw: balanceRaw.toString(),
|
|
137
|
-
balanceFormatted: `${formatted} ${tokenLabel}`,
|
|
138
|
-
},
|
|
139
|
-
};
|
|
140
|
-
} catch (err: any) {
|
|
141
|
-
return { success: false, error: err.message || String(err) };
|
|
142
|
-
}
|
|
143
|
-
},
|
|
144
|
-
};
|
|
145
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
/**
|
|
3
|
-
* @fileoverview Agent-callable tool for freezing (pausing) a card.
|
|
4
|
-
* @module wallet/tools/FreezeCardTool
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { ITool, ToolExecutionContext, ToolExecutionResult } from '@framers/agentos/core/tools/ITool';
|
|
8
|
-
import type { CardManager } from '../cards/CardManager.js';
|
|
9
|
-
|
|
10
|
-
interface FreezeCardInput {}
|
|
11
|
-
|
|
12
|
-
interface FreezeCardOutput {
|
|
13
|
-
state: string;
|
|
14
|
-
message: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function createFreezeCardTool(cardManager: CardManager): ITool<FreezeCardInput, FreezeCardOutput> {
|
|
18
|
-
return {
|
|
19
|
-
id: 'wallet-freeze-card-v1',
|
|
20
|
-
name: 'freeze_card',
|
|
21
|
-
displayName: 'Freeze Card',
|
|
22
|
-
description:
|
|
23
|
-
'Temporarily freeze the agent\'s virtual card. All transactions will be declined until '
|
|
24
|
-
+ 'the card is unfrozen. Useful when suspicious activity is detected or to pause spending.',
|
|
25
|
-
category: 'wallet',
|
|
26
|
-
version: '1.0.0',
|
|
27
|
-
hasSideEffects: true,
|
|
28
|
-
requiredCapabilities: ['capability:wallet', 'capability:wallet_card'],
|
|
29
|
-
|
|
30
|
-
inputSchema: {
|
|
31
|
-
type: 'object',
|
|
32
|
-
properties: {},
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
async execute(_args: FreezeCardInput, context: ToolExecutionContext): Promise<ToolExecutionResult<FreezeCardOutput>> {
|
|
36
|
-
try {
|
|
37
|
-
const agentId = context.gmiId;
|
|
38
|
-
await cardManager.freezeCard(agentId);
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
success: true,
|
|
42
|
-
output: {
|
|
43
|
-
state: 'PAUSED',
|
|
44
|
-
message: 'Card has been frozen. All transactions will be declined until unfrozen.',
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
} catch (err: any) {
|
|
48
|
-
return { success: false, error: err.message || String(err) };
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
};
|
|
52
|
-
}
|