auramaxx 1.0.0-alpha.4
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/LICENSE +26 -0
- package/README.md +112 -0
- package/bin/aurawallet.js +121 -0
- package/docs/ADAPTERS.md +467 -0
- package/docs/API.md +2679 -0
- package/docs/APPS.md +198 -0
- package/docs/ARCHITECTURE.md +350 -0
- package/docs/AUTH.md +698 -0
- package/docs/BEST-PRACTICES.md +121 -0
- package/docs/CLI.md +61 -0
- package/docs/DEVELOPING-APPS.md +452 -0
- package/docs/EXTENSION.md +97 -0
- package/docs/JOBS.md +33 -0
- package/docs/MCP.md +76 -0
- package/docs/PROTOCOL.md +142 -0
- package/docs/SETUP.md +219 -0
- package/docs/WORKSPACE.md +672 -0
- package/docs/agent-auth.md +63 -0
- package/docs/aura-file.md +48 -0
- package/docs/credentials.md +53 -0
- package/docs/external/getting-started.md +65 -0
- package/docs/external/overview.md +45 -0
- package/docs/external/use-cases.md +48 -0
- package/docs/external/why-aura.md +35 -0
- package/docs/jobs/connect-agent.md +77 -0
- package/docs/jobs/migrate-from-dotenv.md +79 -0
- package/docs/jobs/recover-from-lockout.md +72 -0
- package/docs/jobs/secure-ci.md +63 -0
- package/docs/oauth2.md +42 -0
- package/docs/passkeys.md +60 -0
- package/docs/security.md +540 -0
- package/docs/specs/aura-open-protocol.md +61 -0
- package/docs/specs/aura-provider-plugin.md +24 -0
- package/docs/specs/aura-registry-model.md +31 -0
- package/docs/specs/fixtures/invalid-bad-key.aura +1 -0
- package/docs/specs/fixtures/invalid-bad-unicode-escape.aura +1 -0
- package/docs/specs/fixtures/invalid-duplicate-key.aura +2 -0
- package/docs/specs/fixtures/valid-basic.aura +4 -0
- package/docs/specs/fixtures/valid-provider-ref.aura +1 -0
- package/docs/specs/fixtures/valid-quoted-escapes.aura +2 -0
- package/docs/templates/RELEASE_NOTES_TEMPLATE.md +22 -0
- package/docs/totp.md +40 -0
- package/docs/wallet/AI.md +508 -0
- package/docs/wallet/DEVELOPING-STRATEGIES.md +713 -0
- package/docs/wallet/README.md +47 -0
- package/docs/wallet/STRATEGY.md +89 -0
- package/next.config.ts +21 -0
- package/package.json +151 -0
- package/postcss.config.mjs +8 -0
- package/prisma/migrations/20260214170000_baseline/migration.sql +511 -0
- package/prisma/migrations/20260216214537_add_passkey_model/migration.sql +18 -0
- package/prisma/migrations/20260217150500_add_credential_access_audit/migration.sql +31 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +447 -0
- package/public/logo-chevron.svg +31 -0
- package/public/logo-concentric.svg +31 -0
- package/public/logo-crosshatch.svg +39 -0
- package/public/logo-dashed.svg +39 -0
- package/public/logo-horizontal.svg +31 -0
- package/public/logo-m56.svg +64 -0
- package/public/logo.webp +0 -0
- package/scripts/add-app.js +245 -0
- package/scripts/init.sh +57 -0
- package/scripts/migrate-apikeys-to-credentials.ts +35 -0
- package/scripts/sandbox-agent-flow.sh +235 -0
- package/scripts/sandbox.sh +175 -0
- package/scripts/validate-job-docs.mjs +125 -0
- package/server/abi/SwapHelper.json +438 -0
- package/server/cli/approval.ts +447 -0
- package/server/cli/commands/app.ts +204 -0
- package/server/cli/commands/cron.ts +24 -0
- package/server/cli/commands/doctor.ts +1007 -0
- package/server/cli/commands/env.ts +456 -0
- package/server/cli/commands/init.ts +752 -0
- package/server/cli/commands/mcp.ts +125 -0
- package/server/cli/commands/restore.ts +314 -0
- package/server/cli/commands/shell-hook.ts +468 -0
- package/server/cli/commands/start.ts +62 -0
- package/server/cli/commands/status.ts +59 -0
- package/server/cli/commands/stop.ts +14 -0
- package/server/cli/commands/token.ts +180 -0
- package/server/cli/commands/unlock.ts +49 -0
- package/server/cli/commands/vault.ts +417 -0
- package/server/cli/index.ts +328 -0
- package/server/cli/lib/aura-parser.ts +64 -0
- package/server/cli/lib/credential-create.ts +74 -0
- package/server/cli/lib/credential-resolve.ts +254 -0
- package/server/cli/lib/dotenv-migrate.ts +116 -0
- package/server/cli/lib/dotenv-parser.ts +146 -0
- package/server/cli/lib/http.ts +91 -0
- package/server/cli/lib/init-steps.ts +76 -0
- package/server/cli/lib/local-agent-trust.ts +45 -0
- package/server/cli/lib/process.ts +136 -0
- package/server/cli/lib/prompt.ts +85 -0
- package/server/cli/lib/theme.ts +240 -0
- package/server/cli/socket.ts +570 -0
- package/server/cli/transport-client.ts +50 -0
- package/server/cron/index.ts +137 -0
- package/server/cron/job.ts +31 -0
- package/server/cron/jobs/balance-sync.ts +436 -0
- package/server/cron/jobs/incoming-scan.ts +506 -0
- package/server/cron/jobs/native-price.ts +70 -0
- package/server/cron/jobs/orphan-cleanup.ts +40 -0
- package/server/cron/jobs/strategy-runner.ts +175 -0
- package/server/cron/scheduler.ts +125 -0
- package/server/index.ts +406 -0
- package/server/lib/adapters/factory.ts +110 -0
- package/server/lib/adapters/index.ts +19 -0
- package/server/lib/adapters/router.ts +297 -0
- package/server/lib/adapters/telegram.ts +645 -0
- package/server/lib/adapters/types.ts +89 -0
- package/server/lib/adapters/webhook.ts +95 -0
- package/server/lib/address.ts +49 -0
- package/server/lib/agent-auth/contracts.ts +1194 -0
- package/server/lib/agent-profiles.ts +328 -0
- package/server/lib/ai.ts +285 -0
- package/server/lib/api-registry/contracts.ts +86 -0
- package/server/lib/api-registry/validation.ts +172 -0
- package/server/lib/apikey-migration.ts +189 -0
- package/server/lib/app-installer.ts +505 -0
- package/server/lib/app-tokens.ts +247 -0
- package/server/lib/auth.ts +314 -0
- package/server/lib/batch.ts +242 -0
- package/server/lib/cold.ts +874 -0
- package/server/lib/config.ts +381 -0
- package/server/lib/credential-access-audit.ts +85 -0
- package/server/lib/credential-access-policy.ts +110 -0
- package/server/lib/credential-health.ts +343 -0
- package/server/lib/credential-import.ts +487 -0
- package/server/lib/credential-scope.ts +87 -0
- package/server/lib/credential-shares.ts +190 -0
- package/server/lib/credential-transport.ts +342 -0
- package/server/lib/credential-vault.ts +77 -0
- package/server/lib/credentials.ts +333 -0
- package/server/lib/crypto.ts +8 -0
- package/server/lib/db.ts +15 -0
- package/server/lib/defaults.ts +366 -0
- package/server/lib/dex/index.ts +80 -0
- package/server/lib/dex/relay.ts +235 -0
- package/server/lib/dex/types.ts +59 -0
- package/server/lib/dex/uniswap.ts +370 -0
- package/server/lib/e2e-agent/artifacts.ts +36 -0
- package/server/lib/e2e-agent/contracts.ts +112 -0
- package/server/lib/e2e-agent/validation.ts +135 -0
- package/server/lib/encrypt.ts +128 -0
- package/server/lib/error.ts +20 -0
- package/server/lib/events.ts +205 -0
- package/server/lib/hot.ts +357 -0
- package/server/lib/key-fingerprint.ts +28 -0
- package/server/lib/logger.ts +331 -0
- package/server/lib/network.ts +137 -0
- package/server/lib/notifications.ts +219 -0
- package/server/lib/oauth2-refresh.ts +241 -0
- package/server/lib/oursecret.ts +54 -0
- package/server/lib/passkey-credential.ts +360 -0
- package/server/lib/passkey.ts +68 -0
- package/server/lib/permissions.ts +248 -0
- package/server/lib/pino.ts +24 -0
- package/server/lib/policy-preview.ts +138 -0
- package/server/lib/price.ts +338 -0
- package/server/lib/prices.ts +34 -0
- package/server/lib/project-scope.ts +239 -0
- package/server/lib/resolve-action.ts +427 -0
- package/server/lib/resolve.ts +36 -0
- package/server/lib/sessions.ts +632 -0
- package/server/lib/solana/connection.ts +26 -0
- package/server/lib/solana/jupiter.ts +128 -0
- package/server/lib/solana/transfer.ts +108 -0
- package/server/lib/solana/wallet.ts +136 -0
- package/server/lib/strategy/emits.ts +21 -0
- package/server/lib/strategy/engine.ts +1305 -0
- package/server/lib/strategy/executor.ts +115 -0
- package/server/lib/strategy/hook-context.ts +158 -0
- package/server/lib/strategy/hooks.ts +990 -0
- package/server/lib/strategy/index.ts +28 -0
- package/server/lib/strategy/installer.ts +305 -0
- package/server/lib/strategy/loader.ts +256 -0
- package/server/lib/strategy/message.ts +235 -0
- package/server/lib/strategy/repository.ts +218 -0
- package/server/lib/strategy/session-logger.ts +693 -0
- package/server/lib/strategy/sources.ts +288 -0
- package/server/lib/strategy/state.ts +189 -0
- package/server/lib/strategy/templates.ts +403 -0
- package/server/lib/strategy/tick.ts +404 -0
- package/server/lib/strategy/types.ts +230 -0
- package/server/lib/swap.ts +3 -0
- package/server/lib/temp.ts +86 -0
- package/server/lib/token-metadata.ts +86 -0
- package/server/lib/token-safety.ts +200 -0
- package/server/lib/token-search.ts +444 -0
- package/server/lib/totp.ts +194 -0
- package/server/lib/transactions.ts +123 -0
- package/server/lib/transport.ts +75 -0
- package/server/lib/txhistory/decoder.ts +262 -0
- package/server/lib/txhistory/enricher.ts +652 -0
- package/server/lib/txhistory/index.ts +391 -0
- package/server/lib/txhistory/signatures.ts +59 -0
- package/server/lib/verified-summary.ts +421 -0
- package/server/mcp/profile-policy.ts +30 -0
- package/server/mcp/server.ts +619 -0
- package/server/mcp/tools.ts +523 -0
- package/server/middleware/auth.ts +119 -0
- package/server/middleware/requestLogger.ts +84 -0
- package/server/routes/actions.ts +459 -0
- package/server/routes/adapters.ts +703 -0
- package/server/routes/addressbook.ts +113 -0
- package/server/routes/ai.ts +34 -0
- package/server/routes/apikeys.ts +295 -0
- package/server/routes/apps.ts +601 -0
- package/server/routes/auth.ts +457 -0
- package/server/routes/backup.ts +340 -0
- package/server/routes/batch.ts +270 -0
- package/server/routes/bookmarks.ts +162 -0
- package/server/routes/credential-shares.ts +198 -0
- package/server/routes/credential-vaults.ts +154 -0
- package/server/routes/credentials.ts +1290 -0
- package/server/routes/dashboard.ts +71 -0
- package/server/routes/defaults.ts +124 -0
- package/server/routes/fund.ts +229 -0
- package/server/routes/import.ts +352 -0
- package/server/routes/launch.ts +665 -0
- package/server/routes/lock.ts +54 -0
- package/server/routes/logs.ts +68 -0
- package/server/routes/nuke.ts +111 -0
- package/server/routes/passkey-credentials.ts +99 -0
- package/server/routes/passkey.ts +346 -0
- package/server/routes/portfolio.ts +217 -0
- package/server/routes/price.ts +63 -0
- package/server/routes/resolve.ts +31 -0
- package/server/routes/security.ts +45 -0
- package/server/routes/send-evm.ts +241 -0
- package/server/routes/send-solana.ts +281 -0
- package/server/routes/send.ts +178 -0
- package/server/routes/setup.ts +210 -0
- package/server/routes/strategy.ts +894 -0
- package/server/routes/swap-evm.ts +353 -0
- package/server/routes/swap-solana.ts +177 -0
- package/server/routes/swap.ts +356 -0
- package/server/routes/token.ts +247 -0
- package/server/routes/unlock.ts +403 -0
- package/server/routes/wallet-assets.ts +361 -0
- package/server/routes/wallet-transactions.ts +515 -0
- package/server/routes/wallet.ts +710 -0
- package/server/types.ts +146 -0
- package/skills/aurawallet/SKILL.md +739 -0
- package/skills/aurawallet-setup/SKILL.md +74 -0
- package/skills/security-review/SKILL.md +148 -0
- package/src/app/api/agent-requests/route.ts +30 -0
- package/src/app/api/apps/install/route.ts +126 -0
- package/src/app/api/apps/manifests/route.ts +16 -0
- package/src/app/api/apps/static/[...path]/route.ts +57 -0
- package/src/app/api/events/route.ts +92 -0
- package/src/app/api/page.tsx +212 -0
- package/src/app/api/workspace/[id]/apps/[wid]/route.ts +119 -0
- package/src/app/api/workspace/[id]/apps/route.ts +81 -0
- package/src/app/api/workspace/[id]/export/route.ts +67 -0
- package/src/app/api/workspace/[id]/route.ts +168 -0
- package/src/app/api/workspace/auth.ts +34 -0
- package/src/app/api/workspace/config/route.ts +106 -0
- package/src/app/api/workspace/import/route.ts +127 -0
- package/src/app/api/workspace/route.ts +116 -0
- package/src/app/app/page.tsx +2122 -0
- package/src/app/apple-icon.png +0 -0
- package/src/app/docs/page.tsx +178 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +572 -0
- package/src/app/health/page.tsx +5 -0
- package/src/app/hello/page.tsx +15 -0
- package/src/app/icon.png +0 -0
- package/src/app/layout.tsx +34 -0
- package/src/app/page.tsx +986 -0
- package/src/app/providers.tsx +90 -0
- package/src/app/share/[token]/page.tsx +295 -0
- package/src/components/ChainSelector.tsx +144 -0
- package/src/components/HumanActionBar.tsx +695 -0
- package/src/components/NotificationDrawer.tsx +129 -0
- package/src/components/apps/AgentKeysApp.tsx +490 -0
- package/src/components/apps/App.tsx +153 -0
- package/src/components/apps/AppGrid.tsx +15 -0
- package/src/components/apps/DetailedAddressDrawer.tsx +325 -0
- package/src/components/apps/DraggableApp.tsx +562 -0
- package/src/components/apps/IFrameApp.tsx +73 -0
- package/src/components/apps/LogsApp.tsx +360 -0
- package/src/components/apps/SendApp.tsx +394 -0
- package/src/components/apps/SetupWizardApp.tsx +1004 -0
- package/src/components/apps/SystemDefaultsApp.tsx +845 -0
- package/src/components/apps/ThirdPartyApp.tsx +428 -0
- package/src/components/apps/TokenApp.tsx +319 -0
- package/src/components/apps/TransactionsApp.tsx +438 -0
- package/src/components/apps/WalletDetailApp.tsx +1505 -0
- package/src/components/apps/index.ts +13 -0
- package/src/components/design-system/Button.tsx +53 -0
- package/src/components/design-system/ChainIndicator.tsx +65 -0
- package/src/components/design-system/ChainSelector.tsx +137 -0
- package/src/components/design-system/ConfirmationModal.tsx +106 -0
- package/src/components/design-system/ConfirmationPopover.tsx +81 -0
- package/src/components/design-system/Drawer.tsx +123 -0
- package/src/components/design-system/FilterDropdown.tsx +72 -0
- package/src/components/design-system/Modal.tsx +206 -0
- package/src/components/design-system/Popover.tsx +142 -0
- package/src/components/design-system/TextInput.tsx +85 -0
- package/src/components/design-system/Toggle.tsx +58 -0
- package/src/components/design-system/index.ts +11 -0
- package/src/components/docs/DocsThemeToggle.tsx +49 -0
- package/src/components/health/CredentialHealthDashboard.tsx +214 -0
- package/src/components/icons/ChainIcons.tsx +72 -0
- package/src/components/layout/AppStoreDrawer.tsx +369 -0
- package/src/components/layout/ContentArea.tsx +21 -0
- package/src/components/layout/TabBar.tsx +278 -0
- package/src/components/layout/WalletSidebar.tsx +1033 -0
- package/src/components/layout/index.ts +4 -0
- package/src/components/marketing/AuraWalletSpecOverlay.tsx +635 -0
- package/src/components/marketing/DeviceMorphExperience.tsx +216 -0
- package/src/components/vault/ApiKeysConsole.tsx +1080 -0
- package/src/components/vault/AuditConsole.tsx +584 -0
- package/src/components/vault/CredentialDetail.tsx +455 -0
- package/src/components/vault/CredentialEmpty.tsx +55 -0
- package/src/components/vault/CredentialField.tsx +361 -0
- package/src/components/vault/CredentialForm.tsx +1212 -0
- package/src/components/vault/CredentialList.tsx +165 -0
- package/src/components/vault/CredentialRow.tsx +97 -0
- package/src/components/vault/CredentialShareModal.tsx +178 -0
- package/src/components/vault/CredentialVault.tsx +754 -0
- package/src/components/vault/CredentialWalletWidget.tsx +103 -0
- package/src/components/vault/ImportCredentialsModal.tsx +515 -0
- package/src/components/vault/LargeTypeModal.tsx +64 -0
- package/src/components/vault/PasswordGenerator.tsx +224 -0
- package/src/components/vault/TOTPDisplay.tsx +123 -0
- package/src/components/vault/VaultSidebar.tsx +413 -0
- package/src/components/vault/types.ts +54 -0
- package/src/context/AuthContext.tsx +337 -0
- package/src/context/PriceContext.tsx +113 -0
- package/src/context/ThemeContext.tsx +164 -0
- package/src/context/WebSocketContext.tsx +269 -0
- package/src/context/WorkspaceContext.tsx +668 -0
- package/src/hooks/index.ts +3 -0
- package/src/hooks/useAgentActions.ts +368 -0
- package/src/hooks/useBalance.ts +103 -0
- package/src/hooks/useBalances.ts +129 -0
- package/src/instrumentation.ts +12 -0
- package/src/lib/api.ts +449 -0
- package/src/lib/app-loader.ts +148 -0
- package/src/lib/app-registry.ts +178 -0
- package/src/lib/app-sdk.ts +157 -0
- package/src/lib/audit-console-adapter.ts +151 -0
- package/src/lib/auth-client.ts +75 -0
- package/src/lib/config.ts +74 -0
- package/src/lib/crypto.ts +112 -0
- package/src/lib/db.ts +21 -0
- package/src/lib/docs.ts +390 -0
- package/src/lib/events.ts +361 -0
- package/src/lib/pino.ts +24 -0
- package/src/lib/theme-handlers.ts +168 -0
- package/src/lib/theme.ts +351 -0
- package/src/lib/tokenData.ts +378 -0
- package/src/lib/vault-crypto.ts +129 -0
- package/src/lib/websocket-server.ts +302 -0
- package/src/lib/websocket-setup.ts +79 -0
- package/src/lib/wordlist.ts +2050 -0
- package/src/lib/workspace-handlers.ts +285 -0
- package/start.sh +80 -0
- package/tailwind.config.ts +99 -0
- package/tsconfig.json +42 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Router, Request, Response } from 'express';
|
|
2
|
+
import { prisma } from '../lib/db';
|
|
3
|
+
import { listTokensFromDb } from '../lib/sessions';
|
|
4
|
+
import { getAdminTokenHashes } from '../lib/auth';
|
|
5
|
+
import { getErrorMessage } from '../lib/error';
|
|
6
|
+
|
|
7
|
+
const router = Router();
|
|
8
|
+
|
|
9
|
+
// GET /dashboard - Combined view of pending requests and agent tokens
|
|
10
|
+
router.get('/', async (_req: Request, res: Response) => {
|
|
11
|
+
try {
|
|
12
|
+
// Get pending requests
|
|
13
|
+
const pendingActions = await prisma.humanAction.findMany({
|
|
14
|
+
where: {
|
|
15
|
+
status: 'pending',
|
|
16
|
+
NOT: { type: 'strategy:message' },
|
|
17
|
+
},
|
|
18
|
+
orderBy: { createdAt: 'desc' }
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Get all tokens from DB (with isActive flag from memory check)
|
|
22
|
+
const allTokens = await listTokensFromDb();
|
|
23
|
+
|
|
24
|
+
// Exclude admin tokens from DB list — they're added separately from getAdminTokenHashes()
|
|
25
|
+
const nonAdminTokens = allTokens.filter(t => t.agentId !== 'admin');
|
|
26
|
+
|
|
27
|
+
// Active = in memory + not expired + not revoked + (no fund limit OR has remaining)
|
|
28
|
+
const agentActiveTokens = nonAdminTokens.filter(t => t.isActive && (t.limit === 0 || t.remaining > 0));
|
|
29
|
+
|
|
30
|
+
// Inactive = not in memory (server restarted) OR expired OR revoked OR depleted (has limit but none remaining)
|
|
31
|
+
const inactiveTokens = nonAdminTokens.filter(t => !t.isActive || (t.limit > 0 && t.remaining <= 0));
|
|
32
|
+
|
|
33
|
+
// Get admin token hashes and create admin token entries
|
|
34
|
+
const adminHashes = getAdminTokenHashes();
|
|
35
|
+
const adminTokens = adminHashes.map(hash => ({
|
|
36
|
+
tokenHash: hash,
|
|
37
|
+
agentId: 'admin',
|
|
38
|
+
isAdmin: true,
|
|
39
|
+
limit: 0,
|
|
40
|
+
spent: 0,
|
|
41
|
+
remaining: Infinity,
|
|
42
|
+
permissions: ['admin:*'],
|
|
43
|
+
expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000, // 7 days
|
|
44
|
+
isExpired: false,
|
|
45
|
+
isRevoked: false,
|
|
46
|
+
isActive: true,
|
|
47
|
+
}));
|
|
48
|
+
|
|
49
|
+
// Combine: admin tokens first, then agent tokens
|
|
50
|
+
const activeTokens = [...adminTokens, ...agentActiveTokens];
|
|
51
|
+
|
|
52
|
+
res.json({
|
|
53
|
+
success: true,
|
|
54
|
+
requests: pendingActions,
|
|
55
|
+
tokens: {
|
|
56
|
+
active: activeTokens,
|
|
57
|
+
inactive: inactiveTokens
|
|
58
|
+
},
|
|
59
|
+
counts: {
|
|
60
|
+
pendingActions: pendingActions.length,
|
|
61
|
+
activeTokens: activeTokens.length,
|
|
62
|
+
inactiveTokens: inactiveTokens.length
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
} catch (error) {
|
|
66
|
+
const message = getErrorMessage(error);
|
|
67
|
+
res.status(500).json({ error: message });
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
export default router;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* System Defaults Routes
|
|
3
|
+
* ======================
|
|
4
|
+
* Admin-only endpoints for managing centralized system defaults.
|
|
5
|
+
*
|
|
6
|
+
* GET /defaults — All defaults grouped by type
|
|
7
|
+
* PATCH /defaults/:key — Update a single default
|
|
8
|
+
* POST /defaults/reset — Reset one or all defaults to seed values
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { Router, Request, Response } from 'express';
|
|
12
|
+
import { requireWalletAuth } from '../middleware/auth';
|
|
13
|
+
import { requireAdmin } from '../lib/permissions';
|
|
14
|
+
import { getAllDefaults, setDefault, resetDefault, SEED_DEFAULTS, getDefault } from '../lib/defaults';
|
|
15
|
+
import { events } from '../lib/events';
|
|
16
|
+
import { getErrorMessage } from '../lib/error';
|
|
17
|
+
|
|
18
|
+
const router = Router();
|
|
19
|
+
|
|
20
|
+
// All defaults routes require admin access
|
|
21
|
+
router.use(requireWalletAuth, requireAdmin);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* GET /defaults — List all defaults grouped by type
|
|
25
|
+
*/
|
|
26
|
+
router.get('/', async (_req: Request, res: Response) => {
|
|
27
|
+
try {
|
|
28
|
+
const grouped = await getAllDefaults();
|
|
29
|
+
res.json({ success: true, defaults: grouped });
|
|
30
|
+
} catch (error) {
|
|
31
|
+
const message = getErrorMessage(error);
|
|
32
|
+
res.status(500).json({ success: false, error: message });
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* PATCH /defaults/:key — Update a single default value
|
|
38
|
+
* Body: { value: any }
|
|
39
|
+
*/
|
|
40
|
+
router.patch('/:key', async (req: Request<{ key: string }>, res: Response) => {
|
|
41
|
+
try {
|
|
42
|
+
const { key } = req.params;
|
|
43
|
+
const { value } = req.body;
|
|
44
|
+
|
|
45
|
+
if (value === undefined) {
|
|
46
|
+
res.status(400).json({ success: false, error: 'value is required' });
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Validate the key exists in seeds (don't allow creating arbitrary keys via PATCH)
|
|
51
|
+
const seed = SEED_DEFAULTS.find(s => s.key === key);
|
|
52
|
+
if (!seed) {
|
|
53
|
+
res.status(404).json({ success: false, error: `Unknown default key: ${key}` });
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Type-check: ensure value type matches seed type roughly
|
|
58
|
+
const seedType = typeof seed.value;
|
|
59
|
+
const valueType = typeof value;
|
|
60
|
+
|
|
61
|
+
if (seedType === 'number' && valueType !== 'number') {
|
|
62
|
+
res.status(400).json({ success: false, error: `Expected number for ${key}, got ${valueType}` });
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (Array.isArray(seed.value) && !Array.isArray(value)) {
|
|
67
|
+
res.status(400).json({ success: false, error: `Expected array for ${key}` });
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const previousValue = key === 'trust.localProfile'
|
|
72
|
+
? await getDefault<string>('trust.localProfile', 'dev')
|
|
73
|
+
: null;
|
|
74
|
+
|
|
75
|
+
await setDefault(key, value);
|
|
76
|
+
|
|
77
|
+
if (key === 'trust.localProfile') {
|
|
78
|
+
const previousProfile = typeof previousValue === 'string' ? previousValue.trim() : 'dev';
|
|
79
|
+
const nextProfile = typeof value === 'string' ? value.trim() : '';
|
|
80
|
+
const dangerousModeChanged = (previousProfile === 'admin') !== (nextProfile === 'admin');
|
|
81
|
+
|
|
82
|
+
if (dangerousModeChanged) {
|
|
83
|
+
events.custom('trust:local_dangerous_mode_changed', {
|
|
84
|
+
actorType: req.auth?.token?.agentId ? 'agent' : 'admin',
|
|
85
|
+
actorId: req.auth?.token?.agentId ?? 'admin',
|
|
86
|
+
tokenHash: req.auth?.tokenHash,
|
|
87
|
+
key,
|
|
88
|
+
previousValue: previousProfile,
|
|
89
|
+
nextValue: nextProfile,
|
|
90
|
+
timestamp: Date.now(),
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
res.json({ success: true, key, value });
|
|
96
|
+
} catch (error) {
|
|
97
|
+
const message = getErrorMessage(error);
|
|
98
|
+
res.status(500).json({ success: false, error: message });
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* POST /defaults/reset — Reset one or all defaults to seed values
|
|
104
|
+
* Body: { key: string } — use "*" to reset all
|
|
105
|
+
*/
|
|
106
|
+
router.post('/reset', async (req: Request, res: Response) => {
|
|
107
|
+
try {
|
|
108
|
+
const { key } = req.body;
|
|
109
|
+
|
|
110
|
+
if (!key || typeof key !== 'string') {
|
|
111
|
+
res.status(400).json({ success: false, error: 'key is required (use "*" to reset all)' });
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
await resetDefault(key);
|
|
116
|
+
|
|
117
|
+
res.json({ success: true, key, reset: true });
|
|
118
|
+
} catch (error) {
|
|
119
|
+
const message = getErrorMessage(error);
|
|
120
|
+
res.status(500).json({ success: false, error: message });
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
export default router;
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { Router, Request, Response } from 'express';
|
|
2
|
+
import { ethers } from 'ethers';
|
|
3
|
+
import { PublicKey } from '@solana/web3.js';
|
|
4
|
+
import { reserveSpend, releaseSpend, getRemainingByType } from '../lib/sessions';
|
|
5
|
+
import { tokenCanAccessWallet, getHotWallet } from '../lib/hot';
|
|
6
|
+
import {
|
|
7
|
+
isUnlocked, getColdWalletAddress, signWithColdWallet, getSolanaColdKeypair, getSolanaColdAddress,
|
|
8
|
+
isVaultUnlocked, getVaultAddress, getVaultSolanaAddress, getVaultSolanaKeypair, signWithVault, getPrimaryVaultId
|
|
9
|
+
} from '../lib/cold';
|
|
10
|
+
import { prisma } from '../lib/db';
|
|
11
|
+
import { getRpcUrl, resolveChain } from '../lib/config';
|
|
12
|
+
import { logger } from '../lib/logger';
|
|
13
|
+
import { requireWalletAuth } from '../middleware/auth';
|
|
14
|
+
import { hasAnyPermission, isAdmin } from '../lib/permissions';
|
|
15
|
+
import { isSolanaChain, normalizeAddress, getNativeAddress, getNativeCurrency } from '../lib/address';
|
|
16
|
+
import { getSolanaConnection } from '../lib/solana/connection';
|
|
17
|
+
import { buildSolTransfer, sendSolanaTransaction } from '../lib/solana/transfer';
|
|
18
|
+
import { getErrorMessage, HttpError } from '../lib/error';
|
|
19
|
+
|
|
20
|
+
const router = Router();
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* POST /fund - Agent transfers funds from cold wallet to their hot wallet
|
|
24
|
+
*
|
|
25
|
+
* This executes immediately if the cold wallet is unlocked.
|
|
26
|
+
* The agent's spending limit is checked and deducted.
|
|
27
|
+
*
|
|
28
|
+
* Security checks:
|
|
29
|
+
* 1. Valid bearer token (HMAC signature)
|
|
30
|
+
* 2. Token not revoked
|
|
31
|
+
* 3. Token can access the target hot wallet (owns or has walletAccess grant)
|
|
32
|
+
* 4. Token has fund permission
|
|
33
|
+
* 5. Amount within remaining spending limit (fund limit)
|
|
34
|
+
* 6. Cold wallet must be unlocked
|
|
35
|
+
*/
|
|
36
|
+
router.post('/', requireWalletAuth, async (req: Request, res: Response) => {
|
|
37
|
+
let rollback = () => {};
|
|
38
|
+
try {
|
|
39
|
+
const { to, amount, chain } = req.body;
|
|
40
|
+
const auth = req.auth!;
|
|
41
|
+
|
|
42
|
+
// Validate required fields
|
|
43
|
+
if (!to || typeof to !== 'string') {
|
|
44
|
+
res.status(400).json({ error: 'to (hot wallet address) is required' });
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!amount || (typeof amount !== 'string' && typeof amount !== 'number')) {
|
|
49
|
+
res.status(400).json({ error: 'amount is required (in wei for EVM or lamports for Solana)' });
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Amount is in wei (EVM) or lamports (Solana). Parse as BigInt.
|
|
54
|
+
const amountWei = BigInt(amount);
|
|
55
|
+
if (amountWei <= 0n) {
|
|
56
|
+
res.status(400).json({ error: 'amount must be a positive number' });
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Determine chain first (needed to compute decimal amount for limit checks)
|
|
61
|
+
const { targetChain } = resolveChain(chain);
|
|
62
|
+
|
|
63
|
+
const currency = getNativeAddress(targetChain);
|
|
64
|
+
const nativeCurrency = getNativeCurrency(targetChain);
|
|
65
|
+
|
|
66
|
+
// Convert wei/lamports to decimal for limit checks
|
|
67
|
+
const amountNum = isSolanaChain(targetChain)
|
|
68
|
+
? Number(amountWei) / 1e9 // lamports -> SOL
|
|
69
|
+
: parseFloat(ethers.formatEther(amountWei)); // wei -> ETH
|
|
70
|
+
|
|
71
|
+
// Admin bypasses permission checks
|
|
72
|
+
if (!isAdmin(auth)) {
|
|
73
|
+
// Check fund permission
|
|
74
|
+
if (!hasAnyPermission(auth.token.permissions, ['fund'])) {
|
|
75
|
+
logger.permissionDenied('fund', auth.token.agentId, '/fund');
|
|
76
|
+
res.status(403).json({ error: 'Token does not have fund permission' });
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Check if token can access the target wallet
|
|
81
|
+
const canAccess = await tokenCanAccessWallet(auth.tokenHash, auth.token.walletAccess, to);
|
|
82
|
+
if (!canAccess) {
|
|
83
|
+
logger.permissionDenied('wallet_access', auth.token.agentId, '/fund');
|
|
84
|
+
res.status(403).json({ error: 'Token does not have access to this wallet' });
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Reserve spending atomically (prevents TOCTOU race between concurrent requests)
|
|
89
|
+
const reserve = reserveSpend(auth.tokenHash, auth.token, 'fund', amountNum, currency);
|
|
90
|
+
if (!reserve.ok) {
|
|
91
|
+
logger.limitExceeded(auth.token.agentId, 'fund', amountNum, reserve.remaining);
|
|
92
|
+
res.status(403).json({
|
|
93
|
+
error: 'Amount exceeds remaining spending limit',
|
|
94
|
+
remaining: reserve.remaining,
|
|
95
|
+
requested: amountNum
|
|
96
|
+
});
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Set rollback to release reserved spend on early exit or error
|
|
102
|
+
rollback = () => {
|
|
103
|
+
if (!isAdmin(auth)) releaseSpend(auth.tokenHash, 'fund', amountNum, currency);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// Look up which vault the target hot wallet belongs to
|
|
107
|
+
const hotWalletInfo = await getHotWallet(to);
|
|
108
|
+
const vaultId = hotWalletInfo?.coldWalletId || getPrimaryVaultId();
|
|
109
|
+
|
|
110
|
+
// The source vault must be unlocked
|
|
111
|
+
if (vaultId && !isVaultUnlocked(vaultId)) {
|
|
112
|
+
rollback();
|
|
113
|
+
logger.authFailed('Vault locked', '/fund');
|
|
114
|
+
res.status(401).json({ error: `Vault ${vaultId} is locked. Human must unlock it first.` });
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (!isUnlocked()) {
|
|
118
|
+
rollback();
|
|
119
|
+
logger.authFailed('Vault locked', '/fund');
|
|
120
|
+
res.status(401).json({ error: 'Cold wallet is locked. Human must unlock it first.' });
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// --- Solana early branch ---
|
|
125
|
+
if (isSolanaChain(targetChain)) {
|
|
126
|
+
const coldKeypair = vaultId ? getVaultSolanaKeypair(vaultId) : getSolanaColdKeypair();
|
|
127
|
+
const coldAddress = vaultId ? getVaultSolanaAddress(vaultId) : getSolanaColdAddress();
|
|
128
|
+
if (!coldKeypair || !coldAddress) {
|
|
129
|
+
rollback();
|
|
130
|
+
res.status(400).json({ error: 'Solana cold wallet not available' });
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const connection = await getSolanaConnection(targetChain);
|
|
135
|
+
const toPubkey = new PublicKey(to);
|
|
136
|
+
// Pass lamports directly to buildSolTransfer
|
|
137
|
+
const tx = await buildSolTransfer(connection, coldKeypair.publicKey, toPubkey, Number(amountWei));
|
|
138
|
+
const txHash = await sendSolanaTransaction(connection, tx, coldKeypair);
|
|
139
|
+
|
|
140
|
+
// Spend already reserved atomically above
|
|
141
|
+
|
|
142
|
+
await prisma.log.create({
|
|
143
|
+
data: {
|
|
144
|
+
walletAddress: coldAddress,
|
|
145
|
+
title: 'Agent Fund Transfer',
|
|
146
|
+
description: `Transferred ${amountNum} ${nativeCurrency} to hot wallet ${to.slice(0, 10)}...`,
|
|
147
|
+
txHash
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const agentId = !isAdmin(auth) ? auth.token.agentId : undefined;
|
|
152
|
+
logger.fund(to, amountNum.toString(), txHash, agentId);
|
|
153
|
+
|
|
154
|
+
const remaining = isAdmin(auth)
|
|
155
|
+
? Infinity
|
|
156
|
+
: getRemainingByType(auth.tokenHash, auth.token, 'fund', currency);
|
|
157
|
+
|
|
158
|
+
res.json({
|
|
159
|
+
success: true,
|
|
160
|
+
txHash,
|
|
161
|
+
amount: amountNum.toString(),
|
|
162
|
+
from: coldAddress,
|
|
163
|
+
to,
|
|
164
|
+
chain: targetChain,
|
|
165
|
+
remaining
|
|
166
|
+
});
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// --- EVM path ---
|
|
171
|
+
const coldAddress = vaultId ? getVaultAddress(vaultId) : getColdWalletAddress();
|
|
172
|
+
if (!coldAddress) {
|
|
173
|
+
rollback();
|
|
174
|
+
res.status(400).json({ error: 'Cold wallet not available' });
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Execute the transfer — amountWei is already in wei, pass directly
|
|
179
|
+
const provider = new ethers.JsonRpcProvider(await getRpcUrl(targetChain));
|
|
180
|
+
const txHash = vaultId
|
|
181
|
+
? await signWithVault(vaultId, {
|
|
182
|
+
to: to.toLowerCase(),
|
|
183
|
+
value: amountWei,
|
|
184
|
+
from: coldAddress
|
|
185
|
+
}, provider)
|
|
186
|
+
: await signWithColdWallet({
|
|
187
|
+
to: to.toLowerCase(),
|
|
188
|
+
value: amountWei,
|
|
189
|
+
from: coldAddress
|
|
190
|
+
}, provider);
|
|
191
|
+
|
|
192
|
+
// Spend already reserved atomically above
|
|
193
|
+
|
|
194
|
+
// Log the transaction
|
|
195
|
+
await prisma.log.create({
|
|
196
|
+
data: {
|
|
197
|
+
walletAddress: coldAddress,
|
|
198
|
+
title: 'Agent Fund Transfer',
|
|
199
|
+
description: `Transferred ${amountNum} ETH to hot wallet ${to.slice(0, 10)}...`,
|
|
200
|
+
txHash
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// Log fund event
|
|
205
|
+
const agentId = !isAdmin(auth) ? auth.token.agentId : undefined;
|
|
206
|
+
logger.fund(to, amountNum.toString(), txHash, agentId);
|
|
207
|
+
|
|
208
|
+
// Get remaining for response
|
|
209
|
+
const remaining = isAdmin(auth)
|
|
210
|
+
? Infinity
|
|
211
|
+
: getRemainingByType(auth.tokenHash, auth.token, 'fund', currency);
|
|
212
|
+
|
|
213
|
+
res.json({
|
|
214
|
+
success: true,
|
|
215
|
+
txHash,
|
|
216
|
+
amount: amountNum.toString(),
|
|
217
|
+
from: coldAddress,
|
|
218
|
+
to: to.toLowerCase(),
|
|
219
|
+
chain: targetChain,
|
|
220
|
+
remaining
|
|
221
|
+
});
|
|
222
|
+
} catch (error) {
|
|
223
|
+
rollback();
|
|
224
|
+
if (error instanceof HttpError) { res.status(error.status).json({ error: error.message }); return; }
|
|
225
|
+
res.status(400).json({ error: getErrorMessage(error) });
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
export default router;
|