cornerstone-autonomous-agent 1.0.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.
Files changed (41) hide show
  1. package/.env.example +49 -0
  2. package/LICENSE.md +384 -0
  3. package/README.md +163 -0
  4. package/SKILL-clawdhub.md +180 -0
  5. package/adapters/anthropic/tools.json +58 -0
  6. package/adapters/local/README.md +11 -0
  7. package/adapters/openai/openapi.yaml +72 -0
  8. package/adapters/openclaw/SKILL.md +47 -0
  9. package/package.json +71 -0
  10. package/src/agent/agent.js +52 -0
  11. package/src/agent/index.js +4 -0
  12. package/src/agent/llm.js +25 -0
  13. package/src/agent/tools/localTools.js +259 -0
  14. package/src/agent/tools/mcpTools.js +69 -0
  15. package/src/balance.js +264 -0
  16. package/src/check-update.js +191 -0
  17. package/src/contract.js +390 -0
  18. package/src/credit-aptos-agent.js +103 -0
  19. package/src/lib/aptos/balance.js +32 -0
  20. package/src/lib/aptos/config.js +48 -0
  21. package/src/lib/aptos/index.js +4 -0
  22. package/src/lib/aptos/signPayment.js +94 -0
  23. package/src/lib/aptos/wallet.js +143 -0
  24. package/src/lib/chains.js +157 -0
  25. package/src/lib/evm/index.js +1 -0
  26. package/src/lib/evm/signPayment.js +91 -0
  27. package/src/lib/gas.js +186 -0
  28. package/src/lib/mcp/client.js +225 -0
  29. package/src/lib/mcp/index.js +1 -0
  30. package/src/lib/rpc.js +175 -0
  31. package/src/lib/wallet.js +255 -0
  32. package/src/lib/x402/client.js +195 -0
  33. package/src/lib/x402/index.js +7 -0
  34. package/src/lib/x402/types.js +50 -0
  35. package/src/register-aptos-agent.js +92 -0
  36. package/src/run-agent.js +65 -0
  37. package/src/setup-aptos.js +57 -0
  38. package/src/setup.js +104 -0
  39. package/src/show-agent-addresses.js +32 -0
  40. package/src/swap.js +449 -0
  41. package/src/transfer.js +326 -0
@@ -0,0 +1,255 @@
1
+ /**
2
+ * Wallet state management
3
+ * Handles wallet generation, loading, saving, and client creation.
4
+ * Supports EVM_PRIVATE_KEY env (single wallet) or multi-wallet file with optional network (testnet/mainnet).
5
+ */
6
+
7
+ import { existsSync, readFileSync, writeFileSync, chmodSync } from 'fs';
8
+ import { join } from 'path';
9
+ import { homedir } from 'os';
10
+ import { createWalletClient, http } from 'viem';
11
+ import { privateKeyToAccount, generatePrivateKey } from 'viem/accounts';
12
+ import { getChain } from './chains.js';
13
+
14
+ const LEGACY_PATH = join(homedir(), '.evm-wallet.json');
15
+
16
+ function getWalletPath() {
17
+ const envPath = process.env.EVM_WALLET_PATH;
18
+ if (envPath) {
19
+ return envPath.startsWith('~') ? join(homedir(), envPath.slice(1)) : envPath;
20
+ }
21
+ return join(homedir(), '.evm-wallet.json');
22
+ }
23
+
24
+ function getWalletsPath() {
25
+ const base = process.env.EVM_WALLET_PATH
26
+ ? (process.env.EVM_WALLET_PATH.startsWith('~')
27
+ ? join(homedir(), process.env.EVM_WALLET_PATH.slice(1))
28
+ : process.env.EVM_WALLET_PATH)
29
+ : join(homedir(), '.evm-wallets.json');
30
+ return base.endsWith('.json') && base.includes('evm-wallet')
31
+ ? base.replace('.evm-wallet.json', '.evm-wallets.json').replace('.evm-wallet', '.evm-wallets')
32
+ : join(homedir(), '.evm-wallets.json');
33
+ }
34
+
35
+ /**
36
+ * Generate a new wallet
37
+ * @returns {Object} Wallet object with address and private key
38
+ */
39
+ export function generate() {
40
+ const privateKey = generatePrivateKey();
41
+ const account = privateKeyToAccount(privateKey);
42
+ return {
43
+ address: account.address,
44
+ privateKey,
45
+ createdAt: new Date().toISOString(),
46
+ };
47
+ }
48
+
49
+ /**
50
+ * Load default wallet from EVM_PRIVATE_KEY env or state file(s)
51
+ * @returns {Object|null} Wallet object or null if no wallet exists
52
+ */
53
+ export function load() {
54
+ try {
55
+ const pk = (process.env.EVM_PRIVATE_KEY || '').trim();
56
+ if (pk) {
57
+ const normalizedPk = pk.startsWith('0x') ? pk : `0x${pk}`;
58
+ const account = privateKeyToAccount(normalizedPk);
59
+ return {
60
+ address: account.address,
61
+ privateKey: normalizedPk,
62
+ createdAt: new Date().toISOString(),
63
+ };
64
+ }
65
+ const multi = loadAll();
66
+ if (!multi.wallets.length) return null;
67
+ const idx = Math.min(multi.defaultIndex ?? 0, multi.wallets.length - 1);
68
+ return multi.wallets[idx];
69
+ } catch (error) {
70
+ throw new Error(`Failed to load wallet: ${error.message}`);
71
+ }
72
+ }
73
+
74
+ /**
75
+ * @returns {{ wallets: Array<{ address: string, privateKey: string, network?: string, createdAt?: string }>, defaultIndex: number }}
76
+ */
77
+ export function loadAll() {
78
+ try {
79
+ const pk = (process.env.EVM_PRIVATE_KEY || '').trim();
80
+ if (pk) {
81
+ const normalizedPk = pk.startsWith('0x') ? pk : `0x${pk}`;
82
+ const account = privateKeyToAccount(normalizedPk);
83
+ return {
84
+ wallets: [{ address: account.address, privateKey: normalizedPk, createdAt: new Date().toISOString() }],
85
+ defaultIndex: 0,
86
+ };
87
+ }
88
+ const walletsPath = getWalletsPath();
89
+ if (existsSync(walletsPath)) {
90
+ const data = readFileSync(walletsPath, 'utf8');
91
+ const parsed = JSON.parse(data);
92
+ const wallets = Array.isArray(parsed.wallets) ? parsed.wallets : [];
93
+ const defaultIndex = typeof parsed.defaultIndex === 'number' ? parsed.defaultIndex : 0;
94
+ return { wallets, defaultIndex };
95
+ }
96
+ const legacyPath = getWalletPath();
97
+ if (existsSync(legacyPath)) {
98
+ const data = readFileSync(legacyPath, 'utf8');
99
+ const wallet = JSON.parse(data);
100
+ if (wallet.privateKey && wallet.address) {
101
+ const migrated = {
102
+ wallets: [{ ...wallet, createdAt: wallet.createdAt || new Date().toISOString() }],
103
+ defaultIndex: 0,
104
+ };
105
+ saveAll(migrated);
106
+ return migrated;
107
+ }
108
+ }
109
+ return { wallets: [], defaultIndex: 0 };
110
+ } catch (e) {
111
+ throw new Error(`Failed to load EVM wallets: ${e.message}`);
112
+ }
113
+ }
114
+
115
+ /**
116
+ * @param {{ wallets: Array, defaultIndex: number }} data
117
+ */
118
+ export function saveAll(data) {
119
+ try {
120
+ if ((process.env.EVM_PRIVATE_KEY || '').trim()) return;
121
+ const out = {
122
+ wallets: (data.wallets || []).map((w) => ({
123
+ ...w,
124
+ createdAt: w.createdAt || new Date().toISOString(),
125
+ })),
126
+ defaultIndex: data.defaultIndex ?? 0,
127
+ };
128
+ const path = getWalletsPath();
129
+ writeFileSync(path, JSON.stringify(out, null, 2), 'utf8');
130
+ chmodSync(path, 0o600);
131
+ } catch (e) {
132
+ throw new Error(`Failed to save EVM wallets: ${e.message}`);
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Save wallet: add or update. When EVM_PRIVATE_KEY is set, no-op.
138
+ * @param {Object} wallet - Wallet object to save
139
+ * @param {{ setDefault?: boolean }} options
140
+ */
141
+ export function save(wallet, options = {}) {
142
+ if ((process.env.EVM_PRIVATE_KEY || '').trim()) return;
143
+ const data = loadAll();
144
+ const normalized = { ...wallet, createdAt: wallet.createdAt || new Date().toISOString() };
145
+ const idx = data.wallets.findIndex(
146
+ (w) => (w.address || '').toLowerCase() === (wallet.address || '').toLowerCase()
147
+ );
148
+ if (idx >= 0) {
149
+ data.wallets[idx] = normalized;
150
+ } else {
151
+ data.wallets.push(normalized);
152
+ }
153
+ if (options.setDefault !== false && (data.wallets.length === 1 || options.setDefault === true)) {
154
+ const i = data.wallets.findIndex((w) => w.address === wallet.address);
155
+ data.defaultIndex = i >= 0 ? i : data.wallets.length - 1;
156
+ }
157
+ saveAll(data);
158
+ }
159
+
160
+ /**
161
+ * Get viem account from stored wallet (default or by index/address)
162
+ * @param {number|string} [indexOrAddress]
163
+ */
164
+ export function getAccount(indexOrAddress) {
165
+ const wallet = indexOrAddress !== undefined ? getWalletAt(indexOrAddress) : load();
166
+ if (!wallet) {
167
+ throw new Error('No wallet found. Run setup.js or create_evm_wallet first.');
168
+ }
169
+ return privateKeyToAccount(wallet.privateKey);
170
+ }
171
+
172
+ /**
173
+ * Get wallet address (default)
174
+ * @returns {string} Wallet address
175
+ */
176
+ export function getAddress() {
177
+ const wallet = load();
178
+ if (!wallet) {
179
+ throw new Error('No wallet found. Run setup.js or create_evm_wallet first.');
180
+ }
181
+ return wallet.address;
182
+ }
183
+
184
+ /**
185
+ * Get wallet by index or by address. Returns default if no arg.
186
+ * @param {number|string} [indexOrAddress]
187
+ * @returns {Object|null}
188
+ */
189
+ export function getWalletAt(indexOrAddress) {
190
+ const data = loadAll();
191
+ if (data.wallets.length === 0) return null;
192
+ if (typeof indexOrAddress === 'number') {
193
+ return data.wallets[indexOrAddress] ?? null;
194
+ }
195
+ if (typeof indexOrAddress === 'string' && indexOrAddress.trim()) {
196
+ const addr = indexOrAddress.trim().toLowerCase();
197
+ return data.wallets.find((w) => (w.address || '').toLowerCase() === addr) ?? null;
198
+ }
199
+ const idx = Math.min(data.defaultIndex ?? 0, data.wallets.length - 1);
200
+ return data.wallets[idx] ?? null;
201
+ }
202
+
203
+ /**
204
+ * Create viem wallet client for a specific chain (uses default wallet)
205
+ * @param {string} chainName - Chain name
206
+ * @returns {Object} Viem wallet client
207
+ */
208
+ export function getWalletClient(chainName) {
209
+ const chain = getChain(chainName);
210
+ const account = getAccount();
211
+ const viemChain = {
212
+ id: chain.chainId,
213
+ name: chain.name,
214
+ nativeCurrency: {
215
+ name: chain.nativeToken.symbol,
216
+ symbol: chain.nativeToken.symbol,
217
+ decimals: chain.nativeToken.decimals,
218
+ },
219
+ rpcUrls: { default: { http: chain.rpcs }, public: { http: chain.rpcs } },
220
+ blockExplorers: { default: { name: chain.explorer.name, url: chain.explorer.url } },
221
+ };
222
+ return createWalletClient({
223
+ account,
224
+ chain: viemChain,
225
+ transport: http(chain.rpcs[0], { retryCount: 3, timeout: 30_000 }),
226
+ });
227
+ }
228
+
229
+ /**
230
+ * Check if wallet exists (EVM_PRIVATE_KEY or wallet file(s))
231
+ * @returns {boolean}
232
+ */
233
+ export function exists() {
234
+ if ((process.env.EVM_PRIVATE_KEY || '').trim()) return true;
235
+ return existsSync(getWalletsPath()) || existsSync(getWalletPath());
236
+ }
237
+
238
+ /**
239
+ * Get default wallet info (safe - no private key)
240
+ * @returns {Object|null}
241
+ */
242
+ export function getWalletInfo() {
243
+ const wallet = load();
244
+ if (!wallet) return null;
245
+ return { address: wallet.address, network: wallet.network || null, createdAt: wallet.createdAt };
246
+ }
247
+
248
+ /**
249
+ * Get all wallet infos (no private keys)
250
+ * @returns {Array<{ address: string, network?: string }>}
251
+ */
252
+ export function getAllWalletInfos() {
253
+ const data = loadAll();
254
+ return data.wallets.map((w) => ({ address: w.address, network: w.network || null }));
255
+ }
@@ -0,0 +1,195 @@
1
+ /**
2
+ * x402 client: fetch with retry on 402 Payment Required.
3
+ * On 402: parse requirements → build payment (Aptos/EVM) → verify → settle → retry with PAYMENT-SIGNATURE.
4
+ */
5
+
6
+ import { getFirstPaymentRequirements, isAptosNetwork, isEvmNetwork } from './types.js';
7
+
8
+ const DEFAULT_MAX_RETRIES = 2;
9
+ const PAYMENT_SIGNATURE_HEADER = 'PAYMENT-SIGNATURE';
10
+
11
+ /**
12
+ * Normalize facilitator base URL for /verify and /settle.
13
+ * @param {string} url - Base URL (may end with /facilitator or /)
14
+ * @returns {{ verifyUrl: string, settleUrl: string }}
15
+ */
16
+ function normalizeFacilitatorUrl(url) {
17
+ const base = url.replace(/\/+$/, '');
18
+ const hasFacilitator = base.endsWith('/facilitator');
19
+ const prefix = hasFacilitator ? base : base;
20
+ return {
21
+ verifyUrl: `${prefix}/verify`,
22
+ settleUrl: `${prefix}/settle`,
23
+ };
24
+ }
25
+
26
+ /** Timeout for verify (ms); slightly above server/facilitator 30s */
27
+ const VERIFY_TIMEOUT_MS = 35_000;
28
+ /** Timeout for settle (ms); slightly above server/facilitator 60s */
29
+ const SETTLE_TIMEOUT_MS = 65_000;
30
+
31
+ /**
32
+ * Verify payment with facilitator.
33
+ * @param {string} facilitatorUrl - Facilitator base URL
34
+ * @param {Object} paymentPayload - Payment payload from wallet
35
+ * @param {import('./types.js').PaymentRequirements} paymentRequirements - Payment requirements
36
+ * @returns {Promise<Object>} Verification result
37
+ */
38
+ export async function verifyPayment(facilitatorUrl, paymentPayload, paymentRequirements) {
39
+ const { verifyUrl } = normalizeFacilitatorUrl(facilitatorUrl);
40
+ const controller = new AbortController();
41
+ const timeoutId = setTimeout(() => controller.abort(), VERIFY_TIMEOUT_MS);
42
+ try {
43
+ const res = await fetch(verifyUrl, {
44
+ method: 'POST',
45
+ headers: { 'Content-Type': 'application/json' },
46
+ body: JSON.stringify({
47
+ x402Version: 2,
48
+ paymentPayload: {
49
+ x402Version: 2,
50
+ ...paymentPayload,
51
+ network: paymentRequirements.network,
52
+ scheme: paymentRequirements.scheme
53
+ },
54
+ paymentRequirements,
55
+ }),
56
+ signal: controller.signal,
57
+ });
58
+ const body = await res.json().catch(() => ({ isValid: false, invalidReason: 'invalid_response' }));
59
+ if (body && body.isValid === false && body.invalidReason) {
60
+ const extra = [body.message, body.detail, body.error].filter(Boolean).join(' ');
61
+ if (extra) {
62
+ body.invalidReason = body.invalidReason + ` (${extra})`;
63
+ console.warn('Facilitator verify failed:', body.invalidReason, body);
64
+ }
65
+ }
66
+ return body;
67
+ } catch (e) {
68
+ if (e.name === 'AbortError') {
69
+ return { isValid: false, invalidReason: 'facilitator_timeout: Request timed out' };
70
+ }
71
+ throw e;
72
+ } finally {
73
+ clearTimeout(timeoutId);
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Settle payment with facilitator.
79
+ * @param {string} facilitatorUrl - Facilitator base URL
80
+ * @param {Object} paymentPayload - Payment payload from wallet
81
+ * @param {import('./types.js').PaymentRequirements} paymentRequirements - Payment requirements
82
+ * @param {Object} [verification] - Verification result (optional)
83
+ * @returns {Promise<Object>} Settlement result
84
+ */
85
+ export async function settlePayment(facilitatorUrl, paymentPayload, paymentRequirements, verification = {}) {
86
+ const { settleUrl } = normalizeFacilitatorUrl(facilitatorUrl);
87
+ const controller = new AbortController();
88
+ const timeoutId = setTimeout(() => controller.abort(), SETTLE_TIMEOUT_MS);
89
+ try {
90
+ const res = await fetch(settleUrl, {
91
+ method: 'POST',
92
+ headers: { 'Content-Type': 'application/json' },
93
+ body: JSON.stringify({
94
+ x402Version: 2,
95
+ paymentPayload: {
96
+ x402Version: 2,
97
+ ...paymentPayload,
98
+ network: paymentRequirements.network,
99
+ scheme: paymentRequirements.scheme
100
+ },
101
+ paymentRequirements,
102
+ verification,
103
+ }),
104
+ signal: controller.signal,
105
+ });
106
+ return await res.json().catch(() => ({ success: false, errorReason: 'invalid_response' }));
107
+ } catch (e) {
108
+ if (e.name === 'AbortError') {
109
+ return { success: false, errorReason: 'settlement_timeout: Request timed out' };
110
+ }
111
+ throw e;
112
+ } finally {
113
+ clearTimeout(timeoutId);
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Fetch with x402 retry: on 402, pay via facilitator then retry with PAYMENT-SIGNATURE.
119
+ * @param {string} url - Request URL
120
+ * @param {RequestInit} [options] - Fetch options (method, headers, body, etc.)
121
+ * @param {Object} context - x402 context
122
+ * @param {string} context.facilitatorUrl - Facilitator base URL (e.g. https://x402-navy.vercel.app/facilitator)
123
+ * @param {(req: import('./types.js').PaymentRequirements) => Promise<Object>} [context.getAptosPaymentPayload]
124
+ * @param {(req: import('./types.js').PaymentRequirements) => Promise<Object>} [context.getEvmPaymentPayload]
125
+ * @param {number} [context.maxRetries]
126
+ * @returns {Promise<Object>} Parsed JSON response body (after retry if 402)
127
+ */
128
+ export async function fetchWithX402Retry(url, options = {}, context = {}) {
129
+ const maxRetries = context.maxRetries ?? DEFAULT_MAX_RETRIES;
130
+ const { verifyUrl, settleUrl } = normalizeFacilitatorUrl(context.facilitatorUrl || '');
131
+
132
+ const doRequest = async (extraHeaders = {}) => {
133
+ const headers = { ...(options.headers || {}), ...extraHeaders };
134
+ const res = await fetch(url, { ...options, headers });
135
+ const contentType = res.headers.get('content-type') || '';
136
+ const isJson = contentType.includes('application/json');
137
+ const body = isJson ? await res.json().catch(() => ({})) : await res.text().catch(() => '');
138
+
139
+ if (res.status !== 402) {
140
+ if (typeof body === 'object') return body;
141
+ return { raw: body, status: res.status };
142
+ }
143
+
144
+ const requirements = getFirstPaymentRequirements(body);
145
+ if (!requirements) {
146
+ const reason = body?.invalidReason || 'missing_payment_requirements';
147
+ throw new Error(`402: ${reason}`);
148
+ }
149
+
150
+ const network = requirements.network || '';
151
+ let paymentPayload;
152
+ if (isAptosNetwork(network) && context.getAptosPaymentPayload) {
153
+ paymentPayload = await context.getAptosPaymentPayload(requirements);
154
+ } else if (isEvmNetwork(network) && context.getEvmPaymentPayload) {
155
+ paymentPayload = await context.getEvmPaymentPayload(requirements);
156
+ } else {
157
+ throw new Error(`402: unsupported network ${network}`);
158
+ }
159
+
160
+ const verifyRes = await fetch(verifyUrl, {
161
+ method: 'POST',
162
+ headers: { 'Content-Type': 'application/json' },
163
+ body: JSON.stringify({
164
+ paymentPayload: { ...paymentPayload, network, scheme: requirements.scheme },
165
+ paymentRequirements: requirements,
166
+ }),
167
+ });
168
+ const verifyResult = await verifyRes.json().catch(() => ({}));
169
+ if (!verifyResult?.isValid) {
170
+ throw new Error(`402 verify failed: ${verifyResult?.invalidReason || 'invalid'}`);
171
+ }
172
+
173
+ const settleRes = await fetch(settleUrl, {
174
+ method: 'POST',
175
+ headers: { 'Content-Type': 'application/json' },
176
+ body: JSON.stringify({
177
+ paymentPayload: { ...paymentPayload, network, scheme: requirements.scheme },
178
+ paymentRequirements: requirements,
179
+ verification: verifyResult,
180
+ }),
181
+ });
182
+ const settleResult = await settleRes.json().catch(() => ({}));
183
+ if (!settleResult?.success) {
184
+ throw new Error(`402 settle failed: ${settleResult?.errorReason || 'unknown'}`);
185
+ }
186
+
187
+ const signatureValue = typeof paymentPayload === 'string'
188
+ ? paymentPayload
189
+ : (Buffer.isBuffer(paymentPayload) ? paymentPayload.toString('base64') : JSON.stringify(paymentPayload));
190
+ const retryHeaders = { [PAYMENT_SIGNATURE_HEADER]: signatureValue };
191
+ return doRequest(retryHeaders);
192
+ };
193
+
194
+ return doRequest();
195
+ }
@@ -0,0 +1,7 @@
1
+ export { fetchWithX402Retry, verifyPayment, settlePayment } from './client.js';
2
+ export {
3
+ NETWORKS,
4
+ isAptosNetwork,
5
+ isEvmNetwork,
6
+ getFirstPaymentRequirements,
7
+ } from './types.js';
@@ -0,0 +1,50 @@
1
+ /**
2
+ * x402 payment requirement and 402 response types.
3
+ * Used for parsing 402 Payment Required and building payment payloads.
4
+ */
5
+
6
+ /** @typedef {Object} PaymentRequirements
7
+ * @property {string} scheme - e.g. "exact"
8
+ * @property {string} network - e.g. "aptos:2", "eip155:84532"
9
+ * @property {string|number} amount - atomic units
10
+ * @property {string} asset - asset type or contract address
11
+ * @property {string} payTo - recipient address
12
+ * @property {string} [resource] - resource path
13
+ * @property {string} [description] - human-readable description
14
+ */
15
+
16
+ /** @typedef {Object} Payment402Body
17
+ * @property {PaymentRequirements|PaymentRequirements[]} paymentRequirements
18
+ * @property {string} [invalidReason] - e.g. "insufficient_funds"
19
+ * @property {string} [onramp_url]
20
+ */
21
+
22
+ /** Network constants: which tool uses which.
23
+ * - aptos:2, aptos:1: prediction, backtest (Aptos testnet/mainnet)
24
+ * - eip155:8453, eip155:84532: open_bank_account (Base, Base Sepolia)
25
+ */
26
+ export const NETWORKS = {
27
+ APTOS_TESTNET: 'aptos:2',
28
+ APTOS_MAINNET: 'aptos:1',
29
+ BASE: 'eip155:8453',
30
+ BASE_SEPOLIA: 'eip155:84532',
31
+ };
32
+
33
+ export function isAptosNetwork(network) {
34
+ return typeof network === 'string' && network.startsWith('aptos:');
35
+ }
36
+
37
+ export function isEvmNetwork(network) {
38
+ return typeof network === 'string' && network.startsWith('eip155:');
39
+ }
40
+
41
+ /**
42
+ * Normalize 402 body to a single PaymentRequirements object.
43
+ * @param {Payment402Body} body - Parsed 402 response body
44
+ * @returns {PaymentRequirements|null}
45
+ */
46
+ export function getFirstPaymentRequirements(body) {
47
+ if (!body || !body.paymentRequirements) return null;
48
+ const pr = body.paymentRequirements;
49
+ return Array.isArray(pr) ? pr[0] ?? null : pr;
50
+ }
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Register an Aptos agent address on-chain so it can receive tokens.
4
+ * On Aptos, an account must exist before it can receive; the first transfer
5
+ * (or a zero/minimal transfer) creates it. Use this when tokens are "sent"
6
+ * (e.g. from the testnet faucet) but don't arrive at the agent address.
7
+ *
8
+ * Requires a sender with APT on the same network (testnet by default).
9
+ * Set REGISTER_SENDER_PRIVATE_KEY in env (hex, with or without 0x).
10
+ * Or omit to use the agent's own wallet (it must already have some APT).
11
+ *
12
+ * Usage: node src/register-aptos-agent.js [agent_address]
13
+ * agent_address: Aptos address to register (default: default agent wallet)
14
+ * Env: REGISTER_SENDER_PRIVATE_KEY (optional), APTOS_NETWORK=testnet|mainnet|devnet
15
+ */
16
+
17
+ import { getAptosConfig } from './lib/aptos/config.js';
18
+ import { getWalletInfo, load } from './lib/aptos/wallet.js';
19
+
20
+ const MIN_OCTAS = 1; // minimal amount so account is created and receives something
21
+
22
+ function parseArgs() {
23
+ const args = process.argv.slice(2);
24
+ const address = args[0]?.trim();
25
+ return { address };
26
+ }
27
+
28
+ async function main() {
29
+ const { address: argAddress } = parseArgs();
30
+ const network = (process.env.APTOS_NETWORK || 'testnet').toLowerCase();
31
+ const cfg = getAptosConfig(network);
32
+
33
+ let recipientAddress = argAddress;
34
+ if (!recipientAddress) {
35
+ const info = getWalletInfo();
36
+ if (!info?.address) {
37
+ console.error('No agent address provided and no Aptos wallet found. Run: node src/setup-aptos.js');
38
+ process.exit(1);
39
+ }
40
+ recipientAddress = info.address;
41
+ console.log('Using default agent address from wallet:', recipientAddress);
42
+ }
43
+
44
+ const senderKey = (process.env.REGISTER_SENDER_PRIVATE_KEY || '').trim();
45
+ let senderWallet = null;
46
+ if (senderKey && senderKey.length >= 64) {
47
+ const { Account, Ed25519PrivateKey } = await import('@aptos-labs/ts-sdk');
48
+ const pk = new Ed25519PrivateKey(senderKey.startsWith('0x') ? senderKey : '0x' + senderKey);
49
+ const account = Account.fromPrivateKey({ privateKey: pk, legacy: false });
50
+ senderWallet = { address: account.accountAddress.toString(), privateKey: senderKey.startsWith('0x') ? senderKey : '0x' + senderKey };
51
+ } else {
52
+ const w = load();
53
+ if (!w?.privateKey) {
54
+ console.error('Set REGISTER_SENDER_PRIVATE_KEY (hex key with APT on ' + network + ') or ensure agent wallet has APT.');
55
+ process.exit(1);
56
+ }
57
+ senderWallet = w;
58
+ }
59
+
60
+ const { Aptos, AptosConfig, Network, Ed25519PrivateKey } = await import('@aptos-labs/ts-sdk');
61
+ const net = network === 'mainnet' ? Network.MAINNET : network === 'devnet' ? Network.DEVNET : Network.TESTNET;
62
+ const aptosConfig = new AptosConfig({ fullnode: cfg.nodeUrl, network: net });
63
+ const aptos = new Aptos(aptosConfig);
64
+ const privateKey = new Ed25519PrivateKey(senderWallet.privateKey);
65
+ const account = Account.fromPrivateKey({ privateKey, legacy: false });
66
+
67
+ console.log('Registering agent address on', network + ':', recipientAddress);
68
+ console.log('Sender:', senderWallet.address);
69
+ try {
70
+ const builder = await aptos.transaction.build.simple({
71
+ sender: account.accountAddress,
72
+ withFeePayer: false,
73
+ data: {
74
+ function: '0x1::aptos_account::transfer',
75
+ functionArguments: [recipientAddress, BigInt(MIN_OCTAS)],
76
+ },
77
+ });
78
+ const signed = await aptos.transaction.sign({ signer: account, transaction: builder });
79
+ const pending = await aptos.transaction.submit.simple({ transaction: signed });
80
+ await aptos.waitForTransaction({ transactionHash: pending.hash });
81
+ console.log('Done. Agent account is registered. Tx:', pending.hash);
82
+ console.log('You can now fund this address via the faucet or other transfers.');
83
+ } catch (e) {
84
+ console.error('Registration failed:', e.message);
85
+ process.exit(1);
86
+ }
87
+ }
88
+
89
+ main().catch((e) => {
90
+ console.error(e);
91
+ process.exit(1);
92
+ });
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Entrypoint for the autonomous agent (x402 MCP + LangChain.js).
4
+ * Usage: node src/run-agent.js [message]
5
+ * If no message, runs demo prompt.
6
+ */
7
+
8
+ import 'dotenv/config';
9
+ import { createMcpClient } from './lib/mcp/index.js';
10
+ import { buildAptosPaymentPayload } from './lib/aptos/index.js';
11
+ import { getEvmPaymentPayload } from './lib/evm/index.js';
12
+ import { createAgent } from './agent/index.js';
13
+
14
+ const DEMO_PROMPT =
15
+ 'Check my Aptos balance, then run a prediction for AAPL for 30 days and summarize the result.';
16
+
17
+ async function main() {
18
+ const message = process.argv.slice(2).join(' ').trim() || DEMO_PROMPT;
19
+
20
+ const mcpServerUrl = process.env.MCP_SERVER_URL || 'http://localhost:4023';
21
+ const defaultFacilitator = 'https://x402-navy.vercel.app/facilitator';
22
+ let facilitatorUrl = process.env.X402_FACILITATOR_URL || defaultFacilitator;
23
+ if (facilitatorUrl.includes('facilitator.x402.org')) {
24
+ facilitatorUrl = defaultFacilitator;
25
+ }
26
+ const evmFacilitatorUrl = process.env.X402_EVM_FACILITATOR_URL || facilitatorUrl;
27
+
28
+ let getAptosPaymentPayloadFn = null;
29
+ let getEvmPaymentPayloadFn = null;
30
+ try {
31
+ getAptosPaymentPayloadFn = (req) => buildAptosPaymentPayload(req);
32
+ } catch (e) {
33
+ console.warn('Aptos payment not available:', e.message);
34
+ }
35
+ try {
36
+ getEvmPaymentPayloadFn = (req) => getEvmPaymentPayload(req);
37
+ } catch (e) {
38
+ console.warn('EVM payment not available:', e.message);
39
+ }
40
+
41
+ const mcpClient = createMcpClient({
42
+ baseUrl: mcpServerUrl,
43
+ facilitatorUrl,
44
+ evmFacilitatorUrl,
45
+ getAptosPaymentPayload: getAptosPaymentPayloadFn,
46
+ getEvmPaymentPayload: getEvmPaymentPayloadFn,
47
+ });
48
+
49
+ const { runAgent } = await createAgent({ mcpClient });
50
+
51
+ console.log('Running agent with message:', message);
52
+ const result = await runAgent(message);
53
+ const messages = result?.messages ?? [];
54
+ const last = messages[messages.length - 1];
55
+ if (last?.content) {
56
+ console.log('Agent response:', typeof last.content === 'string' ? last.content : JSON.stringify(last.content));
57
+ } else {
58
+ console.log('Result:', JSON.stringify(result, null, 2));
59
+ }
60
+ }
61
+
62
+ main().catch((e) => {
63
+ console.error(e);
64
+ process.exit(1);
65
+ });