auramaxx 0.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.
- package/LICENSE +26 -0
- package/README.md +77 -0
- package/apps/desktop-electron/main.js +428 -0
- package/bin/auramaxx.js +1063 -0
- package/docs/ADAPTERS.md +466 -0
- package/docs/AGENT_SETUP.md +159 -0
- package/docs/API.md +127 -0
- package/docs/APPS.md +199 -0
- package/docs/ARCHITECTURE.md +235 -0
- package/docs/AUTH.md +318 -0
- package/docs/BEST-PRACTICES.md +82 -0
- package/docs/CLI.md +141 -0
- package/docs/DESKTOP_ELECTRON.md +26 -0
- package/docs/DEVELOPING-APPS.md +453 -0
- package/docs/MCP.md +122 -0
- package/docs/PACKAGING_POLICY.md +19 -0
- package/docs/PERMISSION.md +137 -0
- package/docs/PROTOCOL.md +142 -0
- package/docs/README.md +50 -0
- package/docs/SKILLS.md +132 -0
- package/docs/TROUBLESHOOTING.md +376 -0
- package/docs/WORKSPACE.md +673 -0
- package/docs/agent-auth.md +14 -0
- package/docs/api/authentication.md +79 -0
- package/docs/api/secrets/api-keys.md +28 -0
- package/docs/api/secrets/credentials.md +80 -0
- package/docs/api/secrets/sharing.md +48 -0
- package/docs/api/system.md +41 -0
- package/docs/api/wallets/apps-strategies.md +66 -0
- package/docs/api/wallets/core.md +46 -0
- package/docs/api/wallets/data-portfolio.md +42 -0
- package/docs/aura-file.md +48 -0
- package/docs/core-concepts/FEATURES.md +114 -0
- package/docs/credentials.md +120 -0
- package/docs/external/HOW_TO_AURAMAXX/GETTING_SECRETS.md +33 -0
- package/docs/external/HOW_TO_AURAMAXX/README.md +45 -0
- package/docs/external/getting-started.md +10 -0
- package/docs/external/overview.md +19 -0
- package/docs/external/persona-paths.md +7 -0
- package/docs/external/share-secret.md +76 -0
- package/docs/external/why-aura.md +7 -0
- package/docs/security.md +227 -0
- package/docs/templates/RELEASE_NOTES_TEMPLATE.md +22 -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 +28 -0
- package/package.json +167 -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/20260222090000_update_admin_ttl_default/migration.sql +10 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +447 -0
- package/public/logo.webp +0 -0
- package/scripts/add-app.js +245 -0
- package/server/abi/SwapHelper.json +438 -0
- package/server/cli/approval.ts +447 -0
- package/server/cli/commands/actions.ts +474 -0
- package/server/cli/commands/api.ts +220 -0
- package/server/cli/commands/apikey.ts +277 -0
- package/server/cli/commands/app.ts +204 -0
- package/server/cli/commands/auth.ts +464 -0
- package/server/cli/commands/cron.ts +24 -0
- package/server/cli/commands/diary.ts +274 -0
- package/server/cli/commands/doctor.ts +1247 -0
- package/server/cli/commands/env.ts +476 -0
- package/server/cli/commands/experimental.ts +69 -0
- package/server/cli/commands/init.ts +798 -0
- package/server/cli/commands/lock.ts +157 -0
- package/server/cli/commands/mcp.ts +285 -0
- package/server/cli/commands/quickhack.ts +86 -0
- package/server/cli/commands/release-check.ts +231 -0
- package/server/cli/commands/restore.ts +314 -0
- package/server/cli/commands/service.ts +320 -0
- package/server/cli/commands/shell-hook.ts +512 -0
- package/server/cli/commands/skill.ts +216 -0
- package/server/cli/commands/start.ts +139 -0
- package/server/cli/commands/status.ts +59 -0
- package/server/cli/commands/stop.ts +36 -0
- package/server/cli/commands/token.ts +180 -0
- package/server/cli/commands/unlock.ts +50 -0
- package/server/cli/commands/vault.ts +1323 -0
- package/server/cli/commands/wallet.ts +209 -0
- package/server/cli/index.ts +280 -0
- package/server/cli/lib/approval-poll.ts +94 -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 +280 -0
- package/server/cli/lib/dotenv-migrate.ts +116 -0
- package/server/cli/lib/dotenv-parser.ts +146 -0
- package/server/cli/lib/escalation.ts +57 -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/lock-unlock-helper.ts +71 -0
- package/server/cli/lib/process.ts +162 -0
- package/server/cli/lib/prompt.ts +294 -0
- package/server/cli/lib/theme.ts +240 -0
- package/server/cli/socket.ts +579 -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 +420 -0
- package/server/lib/adapters/factory.ts +119 -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 +419 -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 +258 -0
- package/server/lib/app-installer.ts +505 -0
- package/server/lib/app-tokens.ts +247 -0
- package/server/lib/approval-link.ts +27 -0
- package/server/lib/auth.ts +314 -0
- package/server/lib/auto-execute.ts +160 -0
- package/server/lib/batch.ts +242 -0
- package/server/lib/cold.ts +1048 -0
- package/server/lib/config.ts +408 -0
- package/server/lib/credential-access-audit.ts +85 -0
- package/server/lib/credential-access-policy.ts +111 -0
- package/server/lib/credential-health.ts +343 -0
- package/server/lib/credential-import.ts +608 -0
- package/server/lib/credential-scope.ts +102 -0
- package/server/lib/credential-shares.ts +190 -0
- package/server/lib/credential-transport.ts +533 -0
- package/server/lib/credential-vault.ts +77 -0
- package/server/lib/credentials.ts +422 -0
- package/server/lib/crypto.ts +8 -0
- package/server/lib/db.ts +58 -0
- package/server/lib/defaults.ts +386 -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/diary.ts +34 -0
- package/server/lib/dont-ask-again-policy.ts +41 -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 +114 -0
- package/server/lib/error.ts +20 -0
- package/server/lib/events.ts +217 -0
- package/server/lib/feature-flags.ts +93 -0
- package/server/lib/hot.ts +357 -0
- package/server/lib/human-action-summary.ts +80 -0
- package/server/lib/key-fingerprint.ts +28 -0
- package/server/lib/logger.ts +340 -0
- package/server/lib/network.ts +137 -0
- package/server/lib/notifications.ts +230 -0
- package/server/lib/oauth2-refresh.ts +241 -0
- package/server/lib/oursecret.ts +71 -0
- package/server/lib/passkey-credential.ts +360 -0
- package/server/lib/passkey.ts +68 -0
- package/server/lib/permissions.ts +299 -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 +297 -0
- package/server/lib/resolve-action.ts +328 -0
- package/server/lib/resolve.ts +36 -0
- package/server/lib/secret-gist-share.ts +296 -0
- package/server/lib/sessions.ts +634 -0
- package/server/lib/socket-path.ts +56 -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 +159 -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 +237 -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 +84 -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/update-check.ts +35 -0
- package/server/lib/verified-summary.ts +414 -0
- package/server/lib/view-registry.ts +80 -0
- package/server/mcp/profile-policy.ts +30 -0
- package/server/mcp/server.ts +1589 -0
- package/server/mcp/tools.ts +276 -0
- package/server/middleware/auth.ts +119 -0
- package/server/middleware/requestLogger.ts +84 -0
- package/server/routes/actions.ts +539 -0
- package/server/routes/adapters.ts +711 -0
- package/server/routes/addressbook.ts +113 -0
- package/server/routes/ai.ts +34 -0
- package/server/routes/apikeys.ts +343 -0
- package/server/routes/apps.ts +601 -0
- package/server/routes/auth.ts +406 -0
- package/server/routes/backup.ts +404 -0
- package/server/routes/batch.ts +270 -0
- package/server/routes/bookmarks.ts +162 -0
- package/server/routes/credential-shares.ts +380 -0
- package/server/routes/credential-vaults.ts +159 -0
- package/server/routes/credentials.ts +1782 -0
- package/server/routes/dashboard.ts +97 -0
- package/server/routes/defaults.ts +124 -0
- package/server/routes/flags.ts +11 -0
- package/server/routes/fund.ts +225 -0
- package/server/routes/heartbeat.ts +375 -0
- package/server/routes/import.ts +364 -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 +366 -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 +352 -0
- package/server/routes/swap-solana.ts +176 -0
- package/server/routes/swap.ts +356 -0
- package/server/routes/token.ts +247 -0
- package/server/routes/unlock.ts +467 -0
- package/server/routes/views.ts +41 -0
- package/server/routes/wallet-assets.ts +361 -0
- package/server/routes/wallet-transactions.ts +515 -0
- package/server/routes/wallet.ts +709 -0
- package/server/types.ts +146 -0
- package/shared/credential-field-schema.ts +248 -0
- package/skills/auramaxx/HEARTBEAT.md +78 -0
- package/skills/auramaxx/SKILL.md +745 -0
- package/skills/auramaxx/docs/AGENT_SETUP.md +155 -0
- package/skills/auramaxx/docs/API.md +127 -0
- package/skills/auramaxx/docs/AUTH.md +318 -0
- package/skills/auramaxx/docs/CLI.md +130 -0
- package/skills/auramaxx/docs/MCP.md +122 -0
- package/skills/auramaxx/docs/TROUBLESHOOTING.md +357 -0
- package/skills/auramaxx/docs/WORKSPACE.md +673 -0
- package/skills/auramaxx/docs/security.md +227 -0
- package/skills/task-lifecycle/SKILL.md +378 -0
- package/src/app/api/[...doc]/page.tsx +36 -0
- package/src/app/api/agent-requests/route.ts +30 -0
- package/src/app/api/apps/install/route.ts +132 -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/docs/plain/route.ts +74 -0
- package/src/app/api/events/route.ts +92 -0
- package/src/app/api/page.tsx +290 -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 +40 -0
- package/src/app/api/workspace/config/route.ts +121 -0
- package/src/app/api/workspace/import/route.ts +127 -0
- package/src/app/api/workspace/route.ts +116 -0
- package/src/app/app-legacy-do-not-use/page.tsx +2245 -0
- package/src/app/apple-icon.png +0 -0
- package/src/app/approve/[actionId]/page.tsx +409 -0
- package/src/app/docs/DocsPageContent.tsx +269 -0
- package/src/app/docs/[...doc]/page.tsx +41 -0
- package/src/app/docs/page.tsx +38 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +819 -0
- package/src/app/health/page.tsx +5 -0
- package/src/app/hello/page.tsx +102 -0
- package/src/app/icon.png +0 -0
- package/src/app/layout.tsx +39 -0
- package/src/app/page.tsx +1964 -0
- package/src/app/privacy/page.tsx +63 -0
- package/src/app/providers.tsx +87 -0
- package/src/app/share/[token]/page.tsx +295 -0
- package/src/app/terms/page.tsx +80 -0
- package/src/components/ChainSelector.tsx +44 -0
- package/src/components/HumanActionBar.tsx +697 -0
- package/src/components/NotificationDrawer.tsx +387 -0
- package/src/components/PasskeyEnrollmentPrompt.tsx +235 -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 +88 -0
- package/src/components/design-system/ChainIndicator.tsx +65 -0
- package/src/components/design-system/ChainSelector.tsx +147 -0
- package/src/components/design-system/ConfirmationModal.tsx +107 -0
- package/src/components/design-system/ConfirmationPopover.tsx +81 -0
- package/src/components/design-system/DownloadButton.tsx +149 -0
- package/src/components/design-system/Drawer.tsx +133 -0
- package/src/components/design-system/FilterDropdown.tsx +183 -0
- package/src/components/design-system/ItemPicker.tsx +157 -0
- package/src/components/design-system/Modal.tsx +296 -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 +65 -0
- package/src/components/design-system/TyvekCollapsibleSection.tsx +55 -0
- package/src/components/design-system/index.ts +14 -0
- package/src/components/docs/ClientSideMarkdown.tsx +51 -0
- package/src/components/docs/DocsSearchBar.tsx +118 -0
- package/src/components/docs/DocsThemeToggle.tsx +38 -0
- package/src/components/docs/PersistentDocGroup.tsx +91 -0
- package/src/components/docs/ShareUrlButton.tsx +33 -0
- package/src/components/docs/SidebarScrollMemory.tsx +56 -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/CreateViewModal.tsx +88 -0
- package/src/components/layout/LeftRail.tsx +114 -0
- package/src/components/layout/TabBar.tsx +284 -0
- package/src/components/layout/WalletSidebar.tsx +1030 -0
- package/src/components/layout/index.ts +6 -0
- package/src/components/marketing/AuraMaxxSpecOverlay.tsx +653 -0
- package/src/components/marketing/DeviceMorphExperience.tsx +216 -0
- package/src/components/vault/ApiKeysConsole.tsx +1272 -0
- package/src/components/vault/AuditConsole.tsx +600 -0
- package/src/components/vault/CredentialDetail.tsx +625 -0
- package/src/components/vault/CredentialEmpty.tsx +55 -0
- package/src/components/vault/CredentialField.tsx +583 -0
- package/src/components/vault/CredentialForm.tsx +1484 -0
- package/src/components/vault/CredentialList.tsx +265 -0
- package/src/components/vault/CredentialRow.tsx +130 -0
- package/src/components/vault/CredentialShareModal.tsx +273 -0
- package/src/components/vault/CredentialVault.tsx +1662 -0
- package/src/components/vault/CredentialWalletWidget.tsx +103 -0
- package/src/components/vault/DocsConsole.tsx +113 -0
- package/src/components/vault/ImportCredentialsModal.tsx +578 -0
- package/src/components/vault/LargeTypeModal.tsx +88 -0
- package/src/components/vault/PasswordGenerator.tsx +232 -0
- package/src/components/vault/TOTPDisplay.tsx +108 -0
- package/src/components/vault/TotpSetupPanel.tsx +198 -0
- package/src/components/vault/VaultSidebar.tsx +881 -0
- package/src/components/vault/credentialFormName.ts +91 -0
- package/src/components/vault/hooks/useVaultKeyboardShortcuts.ts +69 -0
- package/src/components/vault/types.ts +56 -0
- package/src/context/AuthContext.tsx +365 -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 +4 -0
- package/src/hooks/useAgentActions.ts +552 -0
- package/src/hooks/useBalance.ts +103 -0
- package/src/hooks/useBalances.ts +129 -0
- package/src/hooks/useTheme.ts +156 -0
- package/src/instrumentation.ts +12 -0
- package/src/lib/api-docs.ts +154 -0
- package/src/lib/api.ts +474 -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/credential-field-schema.ts +11 -0
- package/src/lib/crypto.ts +112 -0
- package/src/lib/db.ts +21 -0
- package/src/lib/docs.ts +544 -0
- package/src/lib/events.ts +363 -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/totp-import.ts +57 -0
- package/src/lib/vault-crypto.ts +129 -0
- package/src/lib/view-registry.ts +57 -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 +170 -0
- package/tailwind.config.ts +99 -0
- package/tsconfig.json +42 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { ethers } from 'ethers';
|
|
2
|
+
import { DexAdapter, PoolInfo, SwapParams, SwapTxData } from './types';
|
|
3
|
+
import { getDefaultSync } from '../defaults';
|
|
4
|
+
|
|
5
|
+
const RELAY_API = 'https://api.relay.link';
|
|
6
|
+
|
|
7
|
+
// Native ETH address used by Relay
|
|
8
|
+
const NATIVE_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
9
|
+
|
|
10
|
+
// App fee: 1% (100 bps). Relay keeps 25%, we keep 75%.
|
|
11
|
+
const APP_FEE_BPS = '100';
|
|
12
|
+
|
|
13
|
+
// Supported EVM chain IDs
|
|
14
|
+
const SUPPORTED_CHAINS = new Set([
|
|
15
|
+
1, // Ethereum
|
|
16
|
+
10, // Optimism
|
|
17
|
+
137, // Polygon
|
|
18
|
+
8453, // Base
|
|
19
|
+
42161, // Arbitrum
|
|
20
|
+
324, // zkSync Era
|
|
21
|
+
43114, // Avalanche
|
|
22
|
+
56, // BNB Chain
|
|
23
|
+
250, // Fantom
|
|
24
|
+
59144, // Linea
|
|
25
|
+
534352, // Scroll
|
|
26
|
+
7777777, // Zora
|
|
27
|
+
]);
|
|
28
|
+
|
|
29
|
+
// Relay quote request
|
|
30
|
+
interface RelayQuoteRequest {
|
|
31
|
+
user: string;
|
|
32
|
+
originChainId: number;
|
|
33
|
+
destinationChainId: number;
|
|
34
|
+
originCurrency: string;
|
|
35
|
+
destinationCurrency: string;
|
|
36
|
+
amount: string;
|
|
37
|
+
tradeType: 'EXACT_INPUT';
|
|
38
|
+
slippageTolerance?: string;
|
|
39
|
+
source?: string;
|
|
40
|
+
appFees?: { recipient: string; fee: string }[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Relay quote response types
|
|
44
|
+
interface RelayTxData {
|
|
45
|
+
from: string;
|
|
46
|
+
to: string;
|
|
47
|
+
data: string;
|
|
48
|
+
value: string;
|
|
49
|
+
chainId: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface RelayStepItem {
|
|
53
|
+
status: string;
|
|
54
|
+
data: RelayTxData;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface RelayStep {
|
|
58
|
+
id: string;
|
|
59
|
+
kind: string;
|
|
60
|
+
items: RelayStepItem[];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface RelayQuoteResponse {
|
|
64
|
+
steps: RelayStep[];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Relay price response types
|
|
68
|
+
export interface RelayPriceResponse {
|
|
69
|
+
fees: {
|
|
70
|
+
gas: { amount: string; amountUsd: string; currency: { symbol: string } };
|
|
71
|
+
relayer?: { amount: string; amountUsd: string };
|
|
72
|
+
app?: { amount: string; amountUsd: string };
|
|
73
|
+
};
|
|
74
|
+
details: {
|
|
75
|
+
sender: { amount: string; amountFormatted: string; amountUsd: string; currency: { symbol: string; decimals: number; address: string } };
|
|
76
|
+
recipient: { amount: string; amountFormatted: string; amountUsd: string; currency: { symbol: string; decimals: number; address: string } };
|
|
77
|
+
rate: string;
|
|
78
|
+
slippageTolerance: { origin: { percent: string } };
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get a lightweight price/quote from Relay.
|
|
84
|
+
* Uses /price endpoint (no calldata, lighter than /quote/v2).
|
|
85
|
+
* Returns amounts, fees, exchange rate, and impact.
|
|
86
|
+
*/
|
|
87
|
+
export async function getRelayPrice(params: {
|
|
88
|
+
user: string;
|
|
89
|
+
originChainId: number;
|
|
90
|
+
destinationChainId?: number;
|
|
91
|
+
originCurrency: string;
|
|
92
|
+
destinationCurrency: string;
|
|
93
|
+
amount: string;
|
|
94
|
+
slippageBps?: number;
|
|
95
|
+
}): Promise<RelayPriceResponse> {
|
|
96
|
+
const body: RelayQuoteRequest = {
|
|
97
|
+
user: params.user,
|
|
98
|
+
originChainId: params.originChainId,
|
|
99
|
+
destinationChainId: params.destinationChainId ?? params.originChainId,
|
|
100
|
+
originCurrency: params.originCurrency,
|
|
101
|
+
destinationCurrency: params.destinationCurrency,
|
|
102
|
+
amount: params.amount,
|
|
103
|
+
tradeType: 'EXACT_INPUT',
|
|
104
|
+
source: 'auramaxx',
|
|
105
|
+
appFees: [{ recipient: getDefaultSync('protocol.fee_address', '0xa931533E0E0cCE34fc0FafB25ea2046d391eCAA5'), fee: APP_FEE_BPS }],
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
if (params.slippageBps !== undefined) {
|
|
109
|
+
body.slippageTolerance = params.slippageBps.toString();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const response = await fetch(`${RELAY_API}/price`, {
|
|
113
|
+
method: 'POST',
|
|
114
|
+
headers: { 'Content-Type': 'application/json' },
|
|
115
|
+
body: JSON.stringify(body),
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
if (!response.ok) {
|
|
119
|
+
const text = await response.text();
|
|
120
|
+
throw new Error(`Relay price failed: ${response.status} ${text}`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return response.json();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Get a swap quote from Relay.
|
|
128
|
+
* Returns the raw transaction data for the first incomplete transaction step.
|
|
129
|
+
*/
|
|
130
|
+
async function getRelayQuote(params: {
|
|
131
|
+
user: string;
|
|
132
|
+
originChainId: number;
|
|
133
|
+
destinationChainId?: number;
|
|
134
|
+
originCurrency: string;
|
|
135
|
+
destinationCurrency: string;
|
|
136
|
+
amount: string;
|
|
137
|
+
slippageBps?: number;
|
|
138
|
+
}): Promise<RelayTxData> {
|
|
139
|
+
const body: RelayQuoteRequest = {
|
|
140
|
+
user: params.user,
|
|
141
|
+
originChainId: params.originChainId,
|
|
142
|
+
destinationChainId: params.destinationChainId ?? params.originChainId,
|
|
143
|
+
originCurrency: params.originCurrency,
|
|
144
|
+
destinationCurrency: params.destinationCurrency,
|
|
145
|
+
amount: params.amount,
|
|
146
|
+
tradeType: 'EXACT_INPUT',
|
|
147
|
+
source: 'auramaxx',
|
|
148
|
+
appFees: [{ recipient: getDefaultSync('protocol.fee_address', '0xa931533E0E0cCE34fc0FafB25ea2046d391eCAA5'), fee: APP_FEE_BPS }],
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
if (params.slippageBps !== undefined) {
|
|
152
|
+
body.slippageTolerance = params.slippageBps.toString();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const response = await fetch(`${RELAY_API}/quote/v2`, {
|
|
156
|
+
method: 'POST',
|
|
157
|
+
headers: { 'Content-Type': 'application/json' },
|
|
158
|
+
body: JSON.stringify(body),
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
if (!response.ok) {
|
|
162
|
+
const text = await response.text();
|
|
163
|
+
throw new Error(`Relay quote failed: ${response.status} ${text}`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const data: RelayQuoteResponse = await response.json();
|
|
167
|
+
|
|
168
|
+
// Find the first incomplete transaction step
|
|
169
|
+
for (const step of data.steps) {
|
|
170
|
+
if (step.kind !== 'transaction') continue;
|
|
171
|
+
for (const item of step.items) {
|
|
172
|
+
if (item.status === 'incomplete' && item.data) {
|
|
173
|
+
return item.data;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
throw new Error('Relay quote returned no executable transaction steps');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Relay adapter for same-chain swaps via Relay aggregator API.
|
|
183
|
+
* Supports all major EVM chains. No API key required.
|
|
184
|
+
*/
|
|
185
|
+
export const relayAdapter: DexAdapter = {
|
|
186
|
+
name: 'relay',
|
|
187
|
+
|
|
188
|
+
supportsChain(chainId: number): boolean {
|
|
189
|
+
return SUPPORTED_CHAINS.has(chainId);
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
async detectPool(
|
|
193
|
+
_token: string,
|
|
194
|
+
_provider: ethers.Provider
|
|
195
|
+
): Promise<PoolInfo | null> {
|
|
196
|
+
// Relay is an aggregator -- it finds routes internally.
|
|
197
|
+
// Return a synthetic PoolInfo to indicate Relay can handle this token.
|
|
198
|
+
return { version: 'relay', poolAddress: 'relay' };
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
async buildSwapTx(params: SwapParams): Promise<SwapTxData> {
|
|
202
|
+
const { token, direction, amount, from, chainId, destinationChainId } = params;
|
|
203
|
+
|
|
204
|
+
// Determine origin/destination currencies
|
|
205
|
+
// buy: ETH -> token, sell: token -> ETH
|
|
206
|
+
const originCurrency = direction === 'buy' ? NATIVE_ADDRESS : token;
|
|
207
|
+
const destinationCurrency = direction === 'buy' ? token : NATIVE_ADDRESS;
|
|
208
|
+
|
|
209
|
+
// Amount is already in wei (EVM) or lamports (Solana)
|
|
210
|
+
const amountWei = amount;
|
|
211
|
+
|
|
212
|
+
const txData = await getRelayQuote({
|
|
213
|
+
user: from,
|
|
214
|
+
originChainId: chainId,
|
|
215
|
+
destinationChainId,
|
|
216
|
+
originCurrency,
|
|
217
|
+
destinationCurrency,
|
|
218
|
+
amount: amountWei,
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
to: txData.to,
|
|
223
|
+
data: txData.data,
|
|
224
|
+
value: txData.value || '0',
|
|
225
|
+
};
|
|
226
|
+
},
|
|
227
|
+
|
|
228
|
+
getRouterAddress(): string {
|
|
229
|
+
// Relay uses different contract addresses per chain/tx.
|
|
230
|
+
// Return a descriptive placeholder; the actual `to` comes from buildSwapTx.
|
|
231
|
+
return 'relay';
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
export default relayAdapter;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ethers } from 'ethers';
|
|
2
|
+
|
|
3
|
+
// V4 PoolKey type (Uniswap V4 specific, but may be reused)
|
|
4
|
+
export interface PoolKey {
|
|
5
|
+
currency0: string;
|
|
6
|
+
currency1: string;
|
|
7
|
+
fee: number;
|
|
8
|
+
tickSpacing: number;
|
|
9
|
+
hooks: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Pool detection result
|
|
13
|
+
export interface PoolInfo {
|
|
14
|
+
version: string; // e.g., "v2", "v3", "v4", "stable", "volatile"
|
|
15
|
+
fee?: number; // Fee tier if applicable
|
|
16
|
+
poolKey?: PoolKey; // V4 pool key if applicable
|
|
17
|
+
poolAddress?: string; // Pool/pair address if known
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Swap parameters (DEX-agnostic)
|
|
21
|
+
export interface SwapParams {
|
|
22
|
+
token: string;
|
|
23
|
+
direction: 'buy' | 'sell';
|
|
24
|
+
amount: string; // In wei (EVM) or lamports (Solana)
|
|
25
|
+
minOut: string;
|
|
26
|
+
from: string; // Sender wallet address
|
|
27
|
+
chainId: number; // EVM chain ID
|
|
28
|
+
destinationChainId?: number; // Cross-chain destination (defaults to chainId)
|
|
29
|
+
version?: string; // Pool version override
|
|
30
|
+
fee?: number; // Fee tier override
|
|
31
|
+
poolKey?: PoolKey; // V4 pool key override
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Transaction data result
|
|
35
|
+
export interface SwapTxData {
|
|
36
|
+
to: string;
|
|
37
|
+
data: string;
|
|
38
|
+
value: string; // In wei
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// DEX Adapter interface
|
|
42
|
+
export interface DexAdapter {
|
|
43
|
+
name: string;
|
|
44
|
+
|
|
45
|
+
// Supported on this chain?
|
|
46
|
+
supportsChain(chainId: number): boolean;
|
|
47
|
+
|
|
48
|
+
// Detect if a pool exists for this token
|
|
49
|
+
detectPool(
|
|
50
|
+
token: string,
|
|
51
|
+
provider: ethers.Provider
|
|
52
|
+
): Promise<PoolInfo | null>;
|
|
53
|
+
|
|
54
|
+
// Build swap transaction
|
|
55
|
+
buildSwapTx(params: SwapParams): Promise<SwapTxData>;
|
|
56
|
+
|
|
57
|
+
// Get the router/helper contract address
|
|
58
|
+
getRouterAddress(): string;
|
|
59
|
+
}
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import { ethers } from 'ethers';
|
|
2
|
+
import { DexAdapter, PoolInfo, SwapParams, SwapTxData, PoolKey } from './types';
|
|
3
|
+
import SwapHelperABI from '../../abi/SwapHelper.json';
|
|
4
|
+
|
|
5
|
+
// Constants
|
|
6
|
+
export const SWAP_HELPER = '0xD28f98c89d6F88762377b400936b434731c8a61F'; // SwapHelperV2 (Universal Router)
|
|
7
|
+
export const WETH = '0x4200000000000000000000000000000000000006';
|
|
8
|
+
|
|
9
|
+
// Uniswap Factory addresses on Base
|
|
10
|
+
const V3_FACTORY = '0x33128a8fC17869897dcE68Ed026d694621f6FDfD';
|
|
11
|
+
const V2_FACTORY = '0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6';
|
|
12
|
+
|
|
13
|
+
// V4 PoolManager address fallback (query from SwapHelper.POOL_MANAGER() at runtime)
|
|
14
|
+
const V4_POOL_MANAGER_FALLBACK = '0x6Ab04E3376fB1d12cC0b27E6F2E7485CC8bFCb53';
|
|
15
|
+
|
|
16
|
+
// Initialize event topic for V4 PoolManager
|
|
17
|
+
const INITIALIZE_EVENT_TOPIC = '0x803151a295203f64f7e2ca2db584660e99eaf67eca6f05af1bf0707e7d38f2cf';
|
|
18
|
+
|
|
19
|
+
// V3 fee tiers to check (ordered by likelihood)
|
|
20
|
+
const V3_FEE_TIERS = [3000, 10000, 500] as const;
|
|
21
|
+
|
|
22
|
+
// Known V4 hooks (Base mainnet)
|
|
23
|
+
export const V4_HOOKS: Record<string, string> = {
|
|
24
|
+
clanker: '0x1F98400000000000000000000000000000000004',
|
|
25
|
+
'clanker-dynamic-fee-v2': '0xd60D6B218116cFd801E28F78d011a203D2b068Cc',
|
|
26
|
+
'clanker-static-fee-v2': '0xb429d62f8f3bFFb98CdB9569533eA23bF0Ba28CC',
|
|
27
|
+
'clanker-4.0-a': '0x34a45c6B61876d739400Bd71228CbcbD4F53E8cC',
|
|
28
|
+
'clanker-4.0-b': '0xDd5EeaFf7BD481AD55Db083062b13a3cdf0A68CC',
|
|
29
|
+
zora: '0xe2B4100DE1CD284Bd364f738d1354715515C90C0',
|
|
30
|
+
// doppler: per-token hooks, must provide poolKey manually
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// Minimal V3 Factory ABI
|
|
34
|
+
const V3_FACTORY_ABI = [
|
|
35
|
+
'function getPool(address tokenA, address tokenB, uint24 fee) view returns (address pool)'
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
// Minimal V2 Factory ABI
|
|
39
|
+
const V2_FACTORY_ABI = [
|
|
40
|
+
'function getPair(address tokenA, address tokenB) view returns (address pair)'
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
// DYNAMIC_FEE_FLAG from Uniswap V4 LPFeeLibrary
|
|
44
|
+
const DYNAMIC_FEE_FLAG = 0x800000;
|
|
45
|
+
|
|
46
|
+
// Standard V4 pool params for known hooks
|
|
47
|
+
const V4_POOL_PARAMS: Record<string, { fee: number; tickSpacing: number }> = {
|
|
48
|
+
clanker: { fee: 10000, tickSpacing: 200 }, // 1% (legacy)
|
|
49
|
+
'clanker-dynamic-fee-v2': { fee: DYNAMIC_FEE_FLAG, tickSpacing: 200 }, // v4.1.0
|
|
50
|
+
'clanker-static-fee-v2': { fee: DYNAMIC_FEE_FLAG, tickSpacing: 200 }, // v4.1.0
|
|
51
|
+
'clanker-4.0-a': { fee: DYNAMIC_FEE_FLAG, tickSpacing: 200 }, // v4.0.0 dynamic
|
|
52
|
+
'clanker-4.0-b': { fee: DYNAMIC_FEE_FLAG, tickSpacing: 200 }, // v4.0.0 static
|
|
53
|
+
zora: { fee: 10000, tickSpacing: 200 }, // 1%
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Common no-hook pool params to try (ordered by likelihood)
|
|
57
|
+
const V4_NO_HOOK_PARAMS = [
|
|
58
|
+
{ fee: 3000, tickSpacing: 60 }, // 0.3%
|
|
59
|
+
{ fee: 10000, tickSpacing: 200 }, // 1%
|
|
60
|
+
{ fee: 500, tickSpacing: 10 }, // 0.05%
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get list of known V4 hook names
|
|
65
|
+
*/
|
|
66
|
+
export function getKnownV4Hooks(): string[] {
|
|
67
|
+
return Object.keys(V4_HOOKS);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get the PoolManager address from SwapHelper contract
|
|
72
|
+
*/
|
|
73
|
+
async function getPoolManagerAddress(provider: ethers.Provider): Promise<string> {
|
|
74
|
+
const swapHelper = new ethers.Contract(
|
|
75
|
+
SWAP_HELPER,
|
|
76
|
+
['function POOL_MANAGER() view returns (address)'],
|
|
77
|
+
provider
|
|
78
|
+
);
|
|
79
|
+
try {
|
|
80
|
+
return await swapHelper.POOL_MANAGER();
|
|
81
|
+
} catch {
|
|
82
|
+
return V4_POOL_MANAGER_FALLBACK;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Build a PoolKey for known V4 hooks or no-hook pools
|
|
88
|
+
*
|
|
89
|
+
* @param token - Token address
|
|
90
|
+
* @param hookName - Hook name ('clanker', 'zora', etc.) or 'none' for no-hook pools
|
|
91
|
+
* @returns PoolKey or null if hook not found
|
|
92
|
+
*/
|
|
93
|
+
export function getV4PoolKey(token: string, hookName?: string): PoolKey | null {
|
|
94
|
+
if (!hookName) return null;
|
|
95
|
+
|
|
96
|
+
const name = hookName.toLowerCase();
|
|
97
|
+
|
|
98
|
+
// Handle 'none' - return first no-hook params (caller can iterate if needed)
|
|
99
|
+
if (name === 'none') {
|
|
100
|
+
const params = V4_NO_HOOK_PARAMS[0];
|
|
101
|
+
const [currency0, currency1] = token.toLowerCase() < WETH.toLowerCase()
|
|
102
|
+
? [token, WETH]
|
|
103
|
+
: [WETH, token];
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
currency0,
|
|
107
|
+
currency1,
|
|
108
|
+
fee: params.fee,
|
|
109
|
+
tickSpacing: params.tickSpacing,
|
|
110
|
+
hooks: ethers.ZeroAddress
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const hookAddress = V4_HOOKS[name];
|
|
115
|
+
const params = V4_POOL_PARAMS[name];
|
|
116
|
+
|
|
117
|
+
if (!hookAddress || !params) return null;
|
|
118
|
+
|
|
119
|
+
const [currency0, currency1] = token.toLowerCase() < WETH.toLowerCase()
|
|
120
|
+
? [token, WETH]
|
|
121
|
+
: [WETH, token];
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
currency0,
|
|
125
|
+
currency1,
|
|
126
|
+
fee: params.fee,
|
|
127
|
+
tickSpacing: params.tickSpacing,
|
|
128
|
+
hooks: hookAddress
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Get all possible no-hook PoolKeys for a token
|
|
134
|
+
*/
|
|
135
|
+
export function getV4NoHookPoolKeys(token: string): PoolKey[] {
|
|
136
|
+
const [currency0, currency1] = token.toLowerCase() < WETH.toLowerCase()
|
|
137
|
+
? [token, WETH]
|
|
138
|
+
: [WETH, token];
|
|
139
|
+
|
|
140
|
+
return V4_NO_HOOK_PARAMS.map(params => ({
|
|
141
|
+
currency0,
|
|
142
|
+
currency1,
|
|
143
|
+
fee: params.fee,
|
|
144
|
+
tickSpacing: params.tickSpacing,
|
|
145
|
+
hooks: ethers.ZeroAddress
|
|
146
|
+
}));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Detect V4 pool by querying PoolManager Initialize events
|
|
151
|
+
*
|
|
152
|
+
* @param token - Token address to search for
|
|
153
|
+
* @param provider - Ethers provider
|
|
154
|
+
* @returns PoolKey if found, null otherwise
|
|
155
|
+
*/
|
|
156
|
+
export async function detectV4PoolFromEvents(
|
|
157
|
+
token: string,
|
|
158
|
+
provider: ethers.Provider
|
|
159
|
+
): Promise<PoolKey | null> {
|
|
160
|
+
try {
|
|
161
|
+
const poolManager = await getPoolManagerAddress(provider);
|
|
162
|
+
const tokenPadded = ethers.zeroPadValue(token.toLowerCase(), 32);
|
|
163
|
+
|
|
164
|
+
// Query with token as currency0
|
|
165
|
+
const logs0 = await provider.getLogs({
|
|
166
|
+
address: poolManager,
|
|
167
|
+
topics: [
|
|
168
|
+
INITIALIZE_EVENT_TOPIC,
|
|
169
|
+
null, // poolId - any
|
|
170
|
+
tokenPadded, // currency0
|
|
171
|
+
null // currency1 - any
|
|
172
|
+
],
|
|
173
|
+
fromBlock: 0
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Query with token as currency1
|
|
177
|
+
const logs1 = await provider.getLogs({
|
|
178
|
+
address: poolManager,
|
|
179
|
+
topics: [
|
|
180
|
+
INITIALIZE_EVENT_TOPIC,
|
|
181
|
+
null,
|
|
182
|
+
null,
|
|
183
|
+
tokenPadded // currency1
|
|
184
|
+
],
|
|
185
|
+
fromBlock: 0
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const allLogs = [...logs0, ...logs1];
|
|
189
|
+
if (allLogs.length === 0) return null;
|
|
190
|
+
|
|
191
|
+
// Parse the first matching event
|
|
192
|
+
const log = allLogs[0];
|
|
193
|
+
|
|
194
|
+
// Extract currency0 and currency1 from indexed topics
|
|
195
|
+
const currency0 = ethers.getAddress('0x' + log.topics[2].slice(26));
|
|
196
|
+
const currency1 = ethers.getAddress('0x' + log.topics[3].slice(26));
|
|
197
|
+
|
|
198
|
+
// Decode the data field: fee (uint24), tickSpacing (int24), hooks (address), sqrtPriceX96 (uint160), tick (int24)
|
|
199
|
+
const decoded = ethers.AbiCoder.defaultAbiCoder().decode(
|
|
200
|
+
['uint24', 'int24', 'address', 'uint160', 'int24'],
|
|
201
|
+
log.data
|
|
202
|
+
);
|
|
203
|
+
const [fee, tickSpacing, hooks] = decoded;
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
currency0,
|
|
207
|
+
currency1,
|
|
208
|
+
fee: Number(fee),
|
|
209
|
+
tickSpacing: Number(tickSpacing),
|
|
210
|
+
hooks
|
|
211
|
+
};
|
|
212
|
+
} catch {
|
|
213
|
+
// RPC errors, parsing errors, etc. - return null
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Uniswap adapter for V2/V3/V4 swaps via SwapHelper contract
|
|
220
|
+
*/
|
|
221
|
+
export const uniswapAdapter: DexAdapter = {
|
|
222
|
+
name: 'uniswap',
|
|
223
|
+
|
|
224
|
+
supportsChain(chainId: number): boolean {
|
|
225
|
+
// SwapHelper is deployed on Base
|
|
226
|
+
return chainId === 8453;
|
|
227
|
+
},
|
|
228
|
+
|
|
229
|
+
async detectPool(
|
|
230
|
+
token: string,
|
|
231
|
+
provider: ethers.Provider
|
|
232
|
+
): Promise<PoolInfo | null> {
|
|
233
|
+
// Priority: V4 with known hooks -> V3 -> V2 -> other V4 pools
|
|
234
|
+
|
|
235
|
+
// 1. Try V4 with known hooks first
|
|
236
|
+
const v4PoolKey = await detectV4PoolFromEvents(token, provider);
|
|
237
|
+
if (v4PoolKey) {
|
|
238
|
+
// Check if this pool uses a known hook
|
|
239
|
+
const knownHookAddresses = Object.values(V4_HOOKS).map(h => h.toLowerCase());
|
|
240
|
+
const hasKnownHook = v4PoolKey.hooks !== ethers.ZeroAddress &&
|
|
241
|
+
knownHookAddresses.includes(v4PoolKey.hooks.toLowerCase());
|
|
242
|
+
|
|
243
|
+
if (hasKnownHook) {
|
|
244
|
+
return { version: 'v4', poolKey: v4PoolKey };
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// 2. Check V3 pools
|
|
249
|
+
const v3Factory = new ethers.Contract(V3_FACTORY, V3_FACTORY_ABI, provider);
|
|
250
|
+
for (const fee of V3_FEE_TIERS) {
|
|
251
|
+
try {
|
|
252
|
+
const pool = await v3Factory.getPool(WETH, token, fee);
|
|
253
|
+
if (pool && pool !== ethers.ZeroAddress) {
|
|
254
|
+
return { version: 'v3', fee, poolAddress: pool };
|
|
255
|
+
}
|
|
256
|
+
} catch {
|
|
257
|
+
// Pool doesn't exist for this fee tier
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// 3. Check V2 pair
|
|
262
|
+
const v2Factory = new ethers.Contract(V2_FACTORY, V2_FACTORY_ABI, provider);
|
|
263
|
+
try {
|
|
264
|
+
const pair = await v2Factory.getPair(WETH, token);
|
|
265
|
+
if (pair && pair !== ethers.ZeroAddress) {
|
|
266
|
+
return { version: 'v2', poolAddress: pair };
|
|
267
|
+
}
|
|
268
|
+
} catch {
|
|
269
|
+
// No V2 pair
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// 4. Return other V4 pool (unknown hooks or no hooks) as fallback
|
|
273
|
+
if (v4PoolKey) {
|
|
274
|
+
return { version: 'v4', poolKey: v4PoolKey };
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return null;
|
|
278
|
+
},
|
|
279
|
+
|
|
280
|
+
buildSwapTx(params: SwapParams): SwapTxData {
|
|
281
|
+
const { token, direction, amount, minOut, version, fee, poolKey } = params;
|
|
282
|
+
|
|
283
|
+
const swapHelper = new ethers.Interface(SwapHelperABI);
|
|
284
|
+
|
|
285
|
+
if (direction === 'buy') {
|
|
286
|
+
return buildBuyTx(swapHelper, token, amount, minOut, version || 'v3', fee, poolKey);
|
|
287
|
+
} else {
|
|
288
|
+
return buildSellTx(swapHelper, token, amount, minOut, version || 'v3', fee, poolKey);
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
|
|
292
|
+
getRouterAddress(): string {
|
|
293
|
+
return SWAP_HELPER;
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
function buildBuyTx(
|
|
298
|
+
iface: ethers.Interface,
|
|
299
|
+
token: string,
|
|
300
|
+
amount: string,
|
|
301
|
+
minOut: string,
|
|
302
|
+
version: string,
|
|
303
|
+
poolFee?: number,
|
|
304
|
+
poolKey?: PoolKey
|
|
305
|
+
): SwapTxData {
|
|
306
|
+
const valueWei = BigInt(amount);
|
|
307
|
+
const minOutBn = BigInt(minOut);
|
|
308
|
+
|
|
309
|
+
let data: string;
|
|
310
|
+
|
|
311
|
+
if (version === 'v2') {
|
|
312
|
+
data = iface.encodeFunctionData('snipeV2', [token, minOutBn]);
|
|
313
|
+
} else if (version === 'v3') {
|
|
314
|
+
const fee = poolFee || 3000;
|
|
315
|
+
data = iface.encodeFunctionData('snipeV3', [token, fee, minOutBn]);
|
|
316
|
+
} else if (version === 'v4') {
|
|
317
|
+
if (!poolKey) throw new Error('V4 pool key required');
|
|
318
|
+
data = iface.encodeFunctionData('snipeV4', [
|
|
319
|
+
[poolKey.currency0, poolKey.currency1, poolKey.fee, poolKey.tickSpacing, poolKey.hooks],
|
|
320
|
+
minOutBn
|
|
321
|
+
]);
|
|
322
|
+
} else {
|
|
323
|
+
throw new Error(`Invalid Uniswap version: ${version}`);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return {
|
|
327
|
+
to: SWAP_HELPER,
|
|
328
|
+
data,
|
|
329
|
+
value: valueWei.toString()
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function buildSellTx(
|
|
334
|
+
iface: ethers.Interface,
|
|
335
|
+
token: string,
|
|
336
|
+
amount: string,
|
|
337
|
+
minOut: string,
|
|
338
|
+
version: string,
|
|
339
|
+
poolFee?: number,
|
|
340
|
+
poolKey?: PoolKey
|
|
341
|
+
): SwapTxData {
|
|
342
|
+
const amountIn = BigInt(amount);
|
|
343
|
+
const minOutBn = BigInt(minOut);
|
|
344
|
+
|
|
345
|
+
let data: string;
|
|
346
|
+
|
|
347
|
+
if (version === 'v2') {
|
|
348
|
+
data = iface.encodeFunctionData('sellV2', [token, amountIn, minOutBn]);
|
|
349
|
+
} else if (version === 'v3') {
|
|
350
|
+
const fee = poolFee || 3000;
|
|
351
|
+
data = iface.encodeFunctionData('sellV3', [token, fee, amountIn, minOutBn]);
|
|
352
|
+
} else if (version === 'v4') {
|
|
353
|
+
if (!poolKey) throw new Error('V4 pool key required');
|
|
354
|
+
data = iface.encodeFunctionData('sellV4', [
|
|
355
|
+
[poolKey.currency0, poolKey.currency1, poolKey.fee, poolKey.tickSpacing, poolKey.hooks],
|
|
356
|
+
amountIn,
|
|
357
|
+
minOutBn
|
|
358
|
+
]);
|
|
359
|
+
} else {
|
|
360
|
+
throw new Error(`Invalid Uniswap version: ${version}`);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return {
|
|
364
|
+
to: SWAP_HELPER,
|
|
365
|
+
data,
|
|
366
|
+
value: '0'
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export default uniswapAdapter;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared diary helpers used by heartbeat + MCP flows.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const DIARY_ENTRY_HEADER_REGEX = /^--- \d{2}:\d{2} UTC ---$/gm;
|
|
6
|
+
|
|
7
|
+
export function resolveDiaryDate(value: string | undefined): string | null {
|
|
8
|
+
if (!value) return new Date().toISOString().slice(0, 10);
|
|
9
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) return null;
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function getDiaryCredentialName(date: string): string {
|
|
14
|
+
return `${date}_LOGS`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function getLegacyDiaryCredentialName(date: string): string {
|
|
18
|
+
return `diary-${date}`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function formatDiaryEntry(entry: string): string {
|
|
22
|
+
const time = new Date().toISOString().slice(11, 16);
|
|
23
|
+
return `--- ${time} UTC ---\n${entry.trim()}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function appendDiaryEntry(previousText: string, entryBlock: string): string {
|
|
27
|
+
if (previousText.trim().length === 0) return entryBlock;
|
|
28
|
+
return `${previousText.trimEnd()}\n\n${entryBlock}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function countDiaryEntries(content: string): number {
|
|
32
|
+
const matches = content.match(DIARY_ENTRY_HEADER_REGEX);
|
|
33
|
+
return matches ? matches.length : 0;
|
|
34
|
+
}
|