web3agent 0.1.0 → 0.2.0

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.
@@ -0,0 +1,90 @@
1
+ import {
2
+ getConfig
3
+ } from "./chunk-7QEKU2RP.js";
4
+
5
+ // src/agdp/api.ts
6
+ var AGDP_DEFAULT_URL = "https://acpx.virtuals.io/api";
7
+ function getAgdpBaseUrl() {
8
+ try {
9
+ const config = getConfig();
10
+ return config.agdpApiUrl ?? AGDP_DEFAULT_URL;
11
+ } catch {
12
+ return AGDP_DEFAULT_URL;
13
+ }
14
+ }
15
+ function flattenResponse(body) {
16
+ if (!body || typeof body !== "object") return [];
17
+ const b = body;
18
+ if (Array.isArray(b.data)) {
19
+ return b.data.map((item) => {
20
+ if (typeof item === "object" && item !== null && "attributes" in item) {
21
+ const { id, attributes } = item;
22
+ return { id, ...attributes };
23
+ }
24
+ return item;
25
+ });
26
+ }
27
+ if (Array.isArray(body)) {
28
+ return body;
29
+ }
30
+ return [];
31
+ }
32
+ async function agdpFetch(path, options) {
33
+ const baseUrl = getAgdpBaseUrl();
34
+ const response = await fetch(`${baseUrl}${path}`, {
35
+ ...options,
36
+ headers: {
37
+ "Content-Type": "application/json",
38
+ ...options?.headers
39
+ }
40
+ });
41
+ if (!response.ok) {
42
+ const text = await response.text().catch(() => "");
43
+ throw new Error(`aGDP API error ${response.status}: ${text}`);
44
+ }
45
+ return response.json();
46
+ }
47
+ async function searchOfferings(params) {
48
+ const { query = "", topK = 10 } = params;
49
+ const qs = new URLSearchParams({
50
+ query,
51
+ topK: String(topK),
52
+ searchMode: "hybrid"
53
+ });
54
+ const body = await agdpFetch(`/agents/v5/search?${qs.toString()}`);
55
+ if (Array.isArray(body)) return body;
56
+ return flattenResponse(body);
57
+ }
58
+ async function getOfferingById(offeringId, cachedAgents) {
59
+ const agents = cachedAgents ?? await searchOfferings({ topK: 500 });
60
+ return agents.find((a) => String(a.id) === String(offeringId)) ?? null;
61
+ }
62
+ async function getJobs(params) {
63
+ const { walletAddress, status = "active" } = params;
64
+ const endpoint = status === "completed" ? "/acp/jobs/completed" : "/acp/jobs/active";
65
+ const qs = new URLSearchParams({ walletAddress });
66
+ const body = await agdpFetch(`${endpoint}?${qs.toString()}`);
67
+ if (Array.isArray(body)) return body;
68
+ return flattenResponse(body);
69
+ }
70
+ async function createJobViaApi(params) {
71
+ return agdpFetch("/acp/jobs", {
72
+ method: "POST",
73
+ body: JSON.stringify(params)
74
+ });
75
+ }
76
+ async function createOfferingViaApi(_params) {
77
+ throw new Error(
78
+ "aGDP offering creation requires authenticated API access. Use the aGDP CLI instead: npx virtuals-protocol-acp sell create"
79
+ );
80
+ }
81
+
82
+ export {
83
+ AGDP_DEFAULT_URL,
84
+ getAgdpBaseUrl,
85
+ searchOfferings,
86
+ getOfferingById,
87
+ getJobs,
88
+ createJobViaApi,
89
+ createOfferingViaApi
90
+ };
@@ -0,0 +1,251 @@
1
+ import {
2
+ getChainById,
3
+ getConfig
4
+ } from "./chunk-7QEKU2RP.js";
5
+
6
+ // src/config/wallet-factory.ts
7
+ import { http, createWalletClient } from "viem";
8
+ var RELIABLE_FALLBACK_RPCS = {
9
+ 56: "https://bsc-dataseed.bnbchain.org"
10
+ };
11
+ function getTransportForChain(chainId, config) {
12
+ const resolvedConfig = config ?? getConfig();
13
+ const perChainUrl = resolvedConfig.chainRpcUrls[chainId];
14
+ if (perChainUrl) return http(perChainUrl);
15
+ if (resolvedConfig.rpcUrl && chainId === resolvedConfig.chainId) {
16
+ return http(resolvedConfig.rpcUrl);
17
+ }
18
+ const fallback = RELIABLE_FALLBACK_RPCS[chainId];
19
+ if (fallback) return http(fallback);
20
+ return http();
21
+ }
22
+ function createWalletClientForChain(account, chainId, config) {
23
+ const chain = getChainById(chainId);
24
+ if (!chain) {
25
+ throw new Error(`Unsupported chain ID: ${chainId}`);
26
+ }
27
+ return createWalletClient({ account, chain, transport: getTransportForChain(chainId, config) });
28
+ }
29
+
30
+ // src/wallet/persistence.ts
31
+ import { existsSync } from "fs";
32
+ import { mkdir, open, readFile, rename, unlink } from "fs/promises";
33
+ import { homedir } from "os";
34
+ import { join } from "path";
35
+ import { generatePrivateKey, mnemonicToAccount, privateKeyToAccount } from "viem/accounts";
36
+
37
+ // src/wallet/events.ts
38
+ import { EventEmitter } from "events";
39
+ var WalletEventEmitter = class extends EventEmitter {
40
+ emit(event, ...args) {
41
+ return super.emit(event, ...args);
42
+ }
43
+ on(event, listener) {
44
+ return super.on(event, listener);
45
+ }
46
+ };
47
+ var walletEvents = new WalletEventEmitter();
48
+
49
+ // src/wallet/persistence.ts
50
+ var currentState = {
51
+ mode: "read-only",
52
+ chainId: 1,
53
+ accountIndex: 0,
54
+ addressIndex: 0
55
+ };
56
+ var currentAccount = null;
57
+ function getWalletDir() {
58
+ return join(homedir(), ".web3agent");
59
+ }
60
+ function getWalletPath() {
61
+ return join(getWalletDir(), "wallet.json");
62
+ }
63
+ function getConfiguredChainId() {
64
+ try {
65
+ return getConfig().chainId;
66
+ } catch (_error) {
67
+ return currentState.chainId;
68
+ }
69
+ }
70
+ function getWalletState() {
71
+ return {
72
+ ...currentState,
73
+ chainId: getConfiguredChainId()
74
+ };
75
+ }
76
+ function getActiveAccount() {
77
+ if (!currentAccount) {
78
+ throw new Error("Wallet not initialized \u2014 call initializeWallet() first");
79
+ }
80
+ return currentAccount;
81
+ }
82
+ function resolveFromPrivateKey(privateKey, chainId) {
83
+ const account = privateKeyToAccount(privateKey);
84
+ return {
85
+ account,
86
+ state: {
87
+ mode: "private-key",
88
+ address: account.address,
89
+ chainId,
90
+ accountIndex: 0,
91
+ addressIndex: 0
92
+ }
93
+ };
94
+ }
95
+ function resolveFromMnemonic(mnemonic, chainId, accountIndex, addressIndex) {
96
+ const account = mnemonicToAccount(mnemonic, {
97
+ accountIndex,
98
+ addressIndex
99
+ });
100
+ return {
101
+ account,
102
+ state: {
103
+ mode: "mnemonic",
104
+ address: account.address,
105
+ chainId,
106
+ accountIndex,
107
+ addressIndex
108
+ }
109
+ };
110
+ }
111
+ function resolveEphemeral(chainId) {
112
+ const key = generatePrivateKey();
113
+ const account = privateKeyToAccount(key);
114
+ return {
115
+ account,
116
+ state: {
117
+ mode: "read-only",
118
+ address: account.address,
119
+ chainId,
120
+ accountIndex: 0,
121
+ addressIndex: 0
122
+ }
123
+ };
124
+ }
125
+ async function tryLoadPersistedWallet(chainId, accountIndex, addressIndex) {
126
+ const walletPath = getWalletPath();
127
+ const tmpPath = `${walletPath}.tmp`;
128
+ if (existsSync(tmpPath)) {
129
+ try {
130
+ await unlink(tmpPath);
131
+ } catch {
132
+ }
133
+ }
134
+ if (!existsSync(walletPath)) return null;
135
+ try {
136
+ const raw = await readFile(walletPath, "utf-8");
137
+ const data = JSON.parse(raw);
138
+ if (data.type === "private-key") {
139
+ return resolveFromPrivateKey(data.privateKey, chainId);
140
+ }
141
+ if (data.type === "mnemonic") {
142
+ return resolveFromMnemonic(
143
+ data.mnemonic,
144
+ chainId,
145
+ data.accountIndex ?? accountIndex,
146
+ data.addressIndex ?? addressIndex
147
+ );
148
+ }
149
+ } catch {
150
+ }
151
+ return null;
152
+ }
153
+ async function initializeWallet(config) {
154
+ const { chainId, accountIndex, addressIndex } = config;
155
+ const envKey = config.privateKey;
156
+ if (envKey) {
157
+ const resolved = resolveFromPrivateKey(envKey, chainId);
158
+ currentAccount = resolved.account;
159
+ currentState = resolved.state;
160
+ walletEvents.emit("wallet-changed", currentState);
161
+ return;
162
+ }
163
+ const envMnemonic = config.mnemonic;
164
+ if (envMnemonic) {
165
+ const resolved = resolveFromMnemonic(envMnemonic, chainId, accountIndex, addressIndex);
166
+ currentAccount = resolved.account;
167
+ currentState = resolved.state;
168
+ walletEvents.emit("wallet-changed", currentState);
169
+ return;
170
+ }
171
+ const persisted = await tryLoadPersistedWallet(chainId, accountIndex, addressIndex);
172
+ if (persisted) {
173
+ currentAccount = persisted.account;
174
+ currentState = persisted.state;
175
+ walletEvents.emit("wallet-changed", currentState);
176
+ return;
177
+ }
178
+ const ephemeral = resolveEphemeral(chainId);
179
+ currentAccount = ephemeral.account;
180
+ currentState = ephemeral.state;
181
+ walletEvents.emit("wallet-changed", currentState);
182
+ }
183
+ async function ensureWalletDir() {
184
+ const dir = getWalletDir();
185
+ if (!existsSync(dir)) {
186
+ await mkdir(dir, { recursive: true });
187
+ }
188
+ }
189
+ async function persistWallet(data) {
190
+ await ensureWalletDir();
191
+ const walletPath = getWalletPath();
192
+ const tmpPath = `${walletPath}.tmp`;
193
+ const fd = await open(tmpPath, "w", 384);
194
+ try {
195
+ await fd.writeFile(JSON.stringify(data, null, 2));
196
+ await fd.sync();
197
+ } finally {
198
+ await fd.close();
199
+ }
200
+ await rename(tmpPath, walletPath);
201
+ }
202
+ async function activateWallet(params) {
203
+ const chainId = getConfiguredChainId();
204
+ const accountIndex = params.accountIndex ?? 0;
205
+ const addressIndex = params.addressIndex ?? 0;
206
+ if (params.privateKey) {
207
+ const resolved = resolveFromPrivateKey(params.privateKey, chainId);
208
+ await persistWallet({
209
+ type: "private-key",
210
+ privateKey: params.privateKey,
211
+ address: resolved.account.address
212
+ });
213
+ currentAccount = resolved.account;
214
+ currentState = resolved.state;
215
+ } else if (params.mnemonic) {
216
+ const resolved = resolveFromMnemonic(params.mnemonic, chainId, accountIndex, addressIndex);
217
+ await persistWallet({
218
+ type: "mnemonic",
219
+ mnemonic: params.mnemonic,
220
+ accountIndex,
221
+ addressIndex
222
+ });
223
+ currentAccount = resolved.account;
224
+ currentState = resolved.state;
225
+ } else {
226
+ throw new Error("Either privateKey or mnemonic must be provided");
227
+ }
228
+ walletEvents.emit("wallet-changed", currentState);
229
+ return getWalletState();
230
+ }
231
+ async function deactivateWallet() {
232
+ const walletPath = getWalletPath();
233
+ if (existsSync(walletPath)) {
234
+ await unlink(walletPath);
235
+ }
236
+ const ephemeral = resolveEphemeral(getConfiguredChainId());
237
+ currentAccount = ephemeral.account;
238
+ currentState = ephemeral.state;
239
+ walletEvents.emit("wallet-changed", currentState);
240
+ }
241
+
242
+ export {
243
+ getTransportForChain,
244
+ createWalletClientForChain,
245
+ walletEvents,
246
+ getWalletState,
247
+ getActiveAccount,
248
+ initializeWallet,
249
+ activateWallet,
250
+ deactivateWallet
251
+ };