@waiaas/daemon 2.11.0-rc.8 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/api/middleware/address-validation.d.ts +6 -33
- package/dist/api/middleware/address-validation.d.ts.map +1 -1
- package/dist/api/middleware/address-validation.js +5 -129
- package/dist/api/middleware/address-validation.js.map +1 -1
- package/dist/api/middleware/host-guard.d.ts +1 -1
- package/dist/api/middleware/host-guard.js +2 -2
- package/dist/api/middleware/host-guard.js.map +1 -1
- package/dist/api/middleware/index.d.ts +1 -0
- package/dist/api/middleware/index.d.ts.map +1 -1
- package/dist/api/middleware/index.js +1 -0
- package/dist/api/middleware/index.js.map +1 -1
- package/dist/api/middleware/master-auth.d.ts +2 -5
- package/dist/api/middleware/master-auth.d.ts.map +1 -1
- package/dist/api/middleware/master-auth.js.map +1 -1
- package/dist/api/middleware/rate-limiter.d.ts +51 -0
- package/dist/api/middleware/rate-limiter.d.ts.map +1 -0
- package/dist/api/middleware/rate-limiter.js +146 -0
- package/dist/api/middleware/rate-limiter.js.map +1 -0
- package/dist/api/middleware/siwe-verify.d.ts +6 -26
- package/dist/api/middleware/siwe-verify.d.ts.map +1 -1
- package/dist/api/middleware/siwe-verify.js +5 -50
- package/dist/api/middleware/siwe-verify.js.map +1 -1
- package/dist/api/routes/actions.d.ts +1 -0
- package/dist/api/routes/actions.d.ts.map +1 -1
- package/dist/api/routes/actions.js +52 -4
- package/dist/api/routes/actions.js.map +1 -1
- package/dist/api/routes/admin-actions.d.ts +1 -0
- package/dist/api/routes/admin-actions.d.ts.map +1 -1
- package/dist/api/routes/admin-actions.js +3 -3
- package/dist/api/routes/admin-actions.js.map +1 -1
- package/dist/api/routes/admin-auth.d.ts.map +1 -1
- package/dist/api/routes/admin-auth.js +12 -7
- package/dist/api/routes/admin-auth.js.map +1 -1
- package/dist/api/routes/admin-credentials.js +2 -2
- package/dist/api/routes/admin-credentials.js.map +1 -1
- package/dist/api/routes/admin-monitoring.d.ts +10 -0
- package/dist/api/routes/admin-monitoring.d.ts.map +1 -1
- package/dist/api/routes/admin-monitoring.js +59 -14
- package/dist/api/routes/admin-monitoring.js.map +1 -1
- package/dist/api/routes/admin-notifications.d.ts.map +1 -1
- package/dist/api/routes/admin-notifications.js +2 -15
- package/dist/api/routes/admin-notifications.js.map +1 -1
- package/dist/api/routes/admin-settings.d.ts.map +1 -1
- package/dist/api/routes/admin-settings.js +90 -1
- package/dist/api/routes/admin-settings.js.map +1 -1
- package/dist/api/routes/admin-wallets.d.ts +16 -1
- package/dist/api/routes/admin-wallets.d.ts.map +1 -1
- package/dist/api/routes/admin-wallets.js +64 -75
- package/dist/api/routes/admin-wallets.js.map +1 -1
- package/dist/api/routes/admin.d.ts +1 -0
- package/dist/api/routes/admin.d.ts.map +1 -1
- package/dist/api/routes/admin.js.map +1 -1
- package/dist/api/routes/credentials.js +2 -2
- package/dist/api/routes/credentials.js.map +1 -1
- package/dist/api/routes/defi-positions.js.map +1 -1
- package/dist/api/routes/nfts.js.map +1 -1
- package/dist/api/routes/openapi-schemas.d.ts +412 -12
- package/dist/api/routes/openapi-schemas.d.ts.map +1 -1
- package/dist/api/routes/openapi-schemas.js +38 -5
- package/dist/api/routes/openapi-schemas.js.map +1 -1
- package/dist/api/routes/policies.d.ts +2 -0
- package/dist/api/routes/policies.d.ts.map +1 -1
- package/dist/api/routes/policies.js +55 -6
- package/dist/api/routes/policies.js.map +1 -1
- package/dist/api/routes/rpc-proxy.js.map +1 -1
- package/dist/api/routes/sessions.d.ts.map +1 -1
- package/dist/api/routes/sessions.js +47 -28
- package/dist/api/routes/sessions.js.map +1 -1
- package/dist/api/routes/staking.d.ts.map +1 -1
- package/dist/api/routes/staking.js +4 -76
- package/dist/api/routes/staking.js.map +1 -1
- package/dist/api/routes/tokens.d.ts.map +1 -1
- package/dist/api/routes/tokens.js.map +1 -1
- package/dist/api/routes/transactions.d.ts +1 -0
- package/dist/api/routes/transactions.d.ts.map +1 -1
- package/dist/api/routes/transactions.js +8 -2
- package/dist/api/routes/transactions.js.map +1 -1
- package/dist/api/routes/userop.d.ts.map +1 -1
- package/dist/api/routes/userop.js +0 -2
- package/dist/api/routes/userop.js.map +1 -1
- package/dist/api/routes/wallet-apps.d.ts.map +1 -1
- package/dist/api/routes/wallet-apps.js +20 -13
- package/dist/api/routes/wallet-apps.js.map +1 -1
- package/dist/api/routes/wallet.js.map +1 -1
- package/dist/api/routes/wallets.d.ts.map +1 -1
- package/dist/api/routes/wallets.js +3 -0
- package/dist/api/routes/wallets.js.map +1 -1
- package/dist/api/routes/wc.d.ts.map +1 -1
- package/dist/api/routes/wc.js +13 -8
- package/dist/api/routes/wc.js.map +1 -1
- package/dist/api/routes/x402.d.ts.map +1 -1
- package/dist/api/routes/x402.js +1 -2
- package/dist/api/routes/x402.js.map +1 -1
- package/dist/api/server.d.ts +8 -4
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +46 -5
- package/dist/api/server.js.map +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +1 -1
- package/dist/constants.js.map +1 -1
- package/dist/infrastructure/action/action-provider-registry.d.ts.map +1 -1
- package/dist/infrastructure/action/action-provider-registry.js +2 -3
- package/dist/infrastructure/action/action-provider-registry.js.map +1 -1
- package/dist/infrastructure/action/builtin-metadata.d.ts +22 -0
- package/dist/infrastructure/action/builtin-metadata.d.ts.map +1 -0
- package/dist/infrastructure/action/builtin-metadata.js +29 -0
- package/dist/infrastructure/action/builtin-metadata.js.map +1 -0
- package/dist/infrastructure/adapter-pool.d.ts +2 -1
- package/dist/infrastructure/adapter-pool.d.ts.map +1 -1
- package/dist/infrastructure/adapter-pool.js.map +1 -1
- package/dist/infrastructure/auth/address-validation.d.ts +38 -0
- package/dist/infrastructure/auth/address-validation.d.ts.map +1 -0
- package/dist/infrastructure/auth/address-validation.js +134 -0
- package/dist/infrastructure/auth/address-validation.js.map +1 -0
- package/dist/infrastructure/auth/siwe-verify.d.ts +34 -0
- package/dist/infrastructure/auth/siwe-verify.d.ts.map +1 -0
- package/dist/infrastructure/auth/siwe-verify.js +58 -0
- package/dist/infrastructure/auth/siwe-verify.js.map +1 -0
- package/dist/infrastructure/auth/types.d.ts +12 -0
- package/dist/infrastructure/auth/types.d.ts.map +1 -0
- package/dist/infrastructure/auth/types.js +8 -0
- package/dist/infrastructure/auth/types.js.map +1 -0
- package/dist/infrastructure/config/loader.d.ts +1 -10
- package/dist/infrastructure/config/loader.d.ts.map +1 -1
- package/dist/infrastructure/config/loader.js +0 -2
- package/dist/infrastructure/config/loader.js.map +1 -1
- package/dist/infrastructure/database/migrate.d.ts +6 -18
- package/dist/infrastructure/database/migrate.d.ts.map +1 -1
- package/dist/infrastructure/database/migrate.js +25 -2856
- package/dist/infrastructure/database/migrate.js.map +1 -1
- package/dist/infrastructure/database/migrations/v11-v20.d.ts +17 -0
- package/dist/infrastructure/database/migrations/v11-v20.d.ts.map +1 -0
- package/dist/infrastructure/database/migrations/v11-v20.js +295 -0
- package/dist/infrastructure/database/migrations/v11-v20.js.map +1 -0
- package/dist/infrastructure/database/migrations/v2-v10.d.ts +16 -0
- package/dist/infrastructure/database/migrations/v2-v10.d.ts.map +1 -0
- package/dist/infrastructure/database/migrations/v2-v10.js +539 -0
- package/dist/infrastructure/database/migrations/v2-v10.js.map +1 -0
- package/dist/infrastructure/database/migrations/v21-v30.d.ts +17 -0
- package/dist/infrastructure/database/migrations/v21-v30.d.ts.map +1 -0
- package/dist/infrastructure/database/migrations/v21-v30.js +507 -0
- package/dist/infrastructure/database/migrations/v21-v30.js.map +1 -0
- package/dist/infrastructure/database/migrations/v31-v40.d.ts +17 -0
- package/dist/infrastructure/database/migrations/v31-v40.d.ts.map +1 -0
- package/dist/infrastructure/database/migrations/v31-v40.js +203 -0
- package/dist/infrastructure/database/migrations/v31-v40.js.map +1 -0
- package/dist/infrastructure/database/migrations/v41-v50.d.ts +17 -0
- package/dist/infrastructure/database/migrations/v41-v50.d.ts.map +1 -0
- package/dist/infrastructure/database/migrations/v41-v50.js +188 -0
- package/dist/infrastructure/database/migrations/v41-v50.js.map +1 -0
- package/dist/infrastructure/database/migrations/v51-v59.d.ts +17 -0
- package/dist/infrastructure/database/migrations/v51-v59.d.ts.map +1 -0
- package/dist/infrastructure/database/migrations/v51-v59.js +420 -0
- package/dist/infrastructure/database/migrations/v51-v59.js.map +1 -0
- package/dist/infrastructure/database/schema-ddl.d.ts +24 -0
- package/dist/infrastructure/database/schema-ddl.d.ts.map +1 -0
- package/dist/infrastructure/database/schema-ddl.js +596 -0
- package/dist/infrastructure/database/schema-ddl.js.map +1 -0
- package/dist/infrastructure/database/schema.d.ts +38 -0
- package/dist/infrastructure/database/schema.d.ts.map +1 -1
- package/dist/infrastructure/database/schema.js +2 -0
- package/dist/infrastructure/database/schema.js.map +1 -1
- package/dist/infrastructure/jwt/jwt-secret-manager.d.ts.map +1 -1
- package/dist/infrastructure/jwt/jwt-secret-manager.js +16 -3
- package/dist/infrastructure/jwt/jwt-secret-manager.js.map +1 -1
- package/dist/infrastructure/nft/alchemy-nft-indexer.d.ts.map +1 -1
- package/dist/infrastructure/nft/alchemy-nft-indexer.js +0 -1
- package/dist/infrastructure/nft/alchemy-nft-indexer.js.map +1 -1
- package/dist/infrastructure/nft/helius-nft-indexer.d.ts.map +1 -1
- package/dist/infrastructure/nft/helius-nft-indexer.js +1 -2
- package/dist/infrastructure/nft/helius-nft-indexer.js.map +1 -1
- package/dist/infrastructure/nft/nft-indexer-client.d.ts.map +1 -1
- package/dist/infrastructure/nft/nft-indexer-client.js +0 -2
- package/dist/infrastructure/nft/nft-indexer-client.js.map +1 -1
- package/dist/infrastructure/security/ssrf-guard.d.ts +33 -0
- package/dist/infrastructure/security/ssrf-guard.d.ts.map +1 -0
- package/dist/infrastructure/security/ssrf-guard.js +244 -0
- package/dist/infrastructure/security/ssrf-guard.js.map +1 -0
- package/dist/infrastructure/settings/hot-reload.d.ts +1 -1
- package/dist/infrastructure/settings/hot-reload.d.ts.map +1 -1
- package/dist/infrastructure/settings/hot-reload.js +0 -2
- package/dist/infrastructure/settings/hot-reload.js.map +1 -1
- package/dist/infrastructure/settings/index.d.ts +2 -2
- package/dist/infrastructure/settings/index.d.ts.map +1 -1
- package/dist/infrastructure/settings/index.js +1 -1
- package/dist/infrastructure/settings/index.js.map +1 -1
- package/dist/infrastructure/settings/setting-keys.d.ts +14 -0
- package/dist/infrastructure/settings/setting-keys.d.ts.map +1 -1
- package/dist/infrastructure/settings/setting-keys.js +296 -214
- package/dist/infrastructure/settings/setting-keys.js.map +1 -1
- package/dist/infrastructure/settings/settings-service.d.ts +6 -1
- package/dist/infrastructure/settings/settings-service.d.ts.map +1 -1
- package/dist/infrastructure/settings/settings-service.js +15 -5
- package/dist/infrastructure/settings/settings-service.js.map +1 -1
- package/dist/infrastructure/telegram/telegram-bot-service.d.ts.map +1 -1
- package/dist/infrastructure/telegram/telegram-bot-service.js +3 -2
- package/dist/infrastructure/telegram/telegram-bot-service.js.map +1 -1
- package/dist/infrastructure/token-registry/builtin-tokens.d.ts.map +1 -1
- package/dist/infrastructure/token-registry/builtin-tokens.js +4 -7
- package/dist/infrastructure/token-registry/builtin-tokens.js.map +1 -1
- package/dist/lifecycle/daemon-pipeline.d.ts +49 -0
- package/dist/lifecycle/daemon-pipeline.d.ts.map +1 -0
- package/dist/lifecycle/daemon-pipeline.js +281 -0
- package/dist/lifecycle/daemon-pipeline.js.map +1 -0
- package/dist/lifecycle/daemon-shutdown.d.ts +14 -0
- package/dist/lifecycle/daemon-shutdown.d.ts.map +1 -0
- package/dist/lifecycle/daemon-shutdown.js +176 -0
- package/dist/lifecycle/daemon-shutdown.js.map +1 -0
- package/dist/lifecycle/daemon-startup.d.ts +15 -0
- package/dist/lifecycle/daemon-startup.d.ts.map +1 -0
- package/dist/lifecycle/daemon-startup.js +1527 -0
- package/dist/lifecycle/daemon-startup.js.map +1 -0
- package/dist/lifecycle/daemon.d.ts +171 -114
- package/dist/lifecycle/daemon.d.ts.map +1 -1
- package/dist/lifecycle/daemon.js +22 -1904
- package/dist/lifecycle/daemon.js.map +1 -1
- package/dist/notifications/channels/discord.d.ts.map +1 -1
- package/dist/notifications/channels/discord.js +1 -0
- package/dist/notifications/channels/discord.js.map +1 -1
- package/dist/notifications/channels/slack.d.ts.map +1 -1
- package/dist/notifications/channels/slack.js +1 -0
- package/dist/notifications/channels/slack.js.map +1 -1
- package/dist/notifications/index.d.ts +0 -1
- package/dist/notifications/index.d.ts.map +1 -1
- package/dist/notifications/index.js +0 -1
- package/dist/notifications/index.js.map +1 -1
- package/dist/notifications/notification-service.d.ts.map +1 -1
- package/dist/notifications/notification-service.js +8 -6
- package/dist/notifications/notification-service.js.map +1 -1
- package/dist/pipeline/database-policy-engine.d.ts +18 -438
- package/dist/pipeline/database-policy-engine.d.ts.map +1 -1
- package/dist/pipeline/database-policy-engine.js +154 -1321
- package/dist/pipeline/database-policy-engine.js.map +1 -1
- package/dist/pipeline/dry-run.d.ts +5 -2
- package/dist/pipeline/dry-run.d.ts.map +1 -1
- package/dist/pipeline/dry-run.js +102 -8
- package/dist/pipeline/dry-run.js.map +1 -1
- package/dist/pipeline/evaluators/allowed-tokens.d.ts +28 -0
- package/dist/pipeline/evaluators/allowed-tokens.d.ts.map +1 -0
- package/dist/pipeline/evaluators/allowed-tokens.js +129 -0
- package/dist/pipeline/evaluators/allowed-tokens.js.map +1 -0
- package/dist/pipeline/evaluators/approved-spenders.d.ts +26 -0
- package/dist/pipeline/evaluators/approved-spenders.d.ts.map +1 -0
- package/dist/pipeline/evaluators/approved-spenders.js +115 -0
- package/dist/pipeline/evaluators/approved-spenders.js.map +1 -0
- package/dist/pipeline/evaluators/contract-whitelist.d.ts +28 -0
- package/dist/pipeline/evaluators/contract-whitelist.d.ts.map +1 -0
- package/dist/pipeline/evaluators/contract-whitelist.js +168 -0
- package/dist/pipeline/evaluators/contract-whitelist.js.map +1 -0
- package/dist/pipeline/evaluators/helpers.d.ts +9 -0
- package/dist/pipeline/evaluators/helpers.d.ts.map +1 -0
- package/dist/pipeline/evaluators/helpers.js +13 -0
- package/dist/pipeline/evaluators/helpers.js.map +1 -0
- package/dist/pipeline/evaluators/lending-asset-whitelist.d.ts +18 -0
- package/dist/pipeline/evaluators/lending-asset-whitelist.d.ts.map +1 -0
- package/dist/pipeline/evaluators/lending-asset-whitelist.js +44 -0
- package/dist/pipeline/evaluators/lending-asset-whitelist.js.map +1 -0
- package/dist/pipeline/evaluators/lending-ltv-limit.d.ts +24 -0
- package/dist/pipeline/evaluators/lending-ltv-limit.d.ts.map +1 -0
- package/dist/pipeline/evaluators/lending-ltv-limit.js +130 -0
- package/dist/pipeline/evaluators/lending-ltv-limit.js.map +1 -0
- package/dist/pipeline/evaluators/spending-limit.d.ts +46 -0
- package/dist/pipeline/evaluators/spending-limit.d.ts.map +1 -0
- package/dist/pipeline/evaluators/spending-limit.js +241 -0
- package/dist/pipeline/evaluators/spending-limit.js.map +1 -0
- package/dist/pipeline/evaluators/types.d.ts +71 -0
- package/dist/pipeline/evaluators/types.d.ts.map +1 -0
- package/dist/pipeline/evaluators/types.js +7 -0
- package/dist/pipeline/evaluators/types.js.map +1 -0
- package/dist/pipeline/external-action-pipeline.js.map +1 -1
- package/dist/pipeline/gas-condition-tracker.d.ts +1 -1
- package/dist/pipeline/gas-condition-tracker.js +1 -1
- package/dist/pipeline/pipeline-helpers.d.ts +146 -0
- package/dist/pipeline/pipeline-helpers.d.ts.map +1 -0
- package/dist/pipeline/pipeline-helpers.js +260 -0
- package/dist/pipeline/pipeline-helpers.js.map +1 -0
- package/dist/pipeline/pipeline.d.ts +1 -0
- package/dist/pipeline/pipeline.d.ts.map +1 -1
- package/dist/pipeline/pipeline.js +3 -2
- package/dist/pipeline/pipeline.js.map +1 -1
- package/dist/pipeline/resolve-effective-amount-usd.d.ts.map +1 -1
- package/dist/pipeline/resolve-effective-amount-usd.js +4 -10
- package/dist/pipeline/resolve-effective-amount-usd.js.map +1 -1
- package/dist/pipeline/sign-message.js +1 -1
- package/dist/pipeline/sign-message.js.map +1 -1
- package/dist/pipeline/sleep.d.ts +1 -5
- package/dist/pipeline/sleep.d.ts.map +1 -1
- package/dist/pipeline/sleep.js +2 -7
- package/dist/pipeline/sleep.js.map +1 -1
- package/dist/pipeline/stage1-validate.d.ts +8 -0
- package/dist/pipeline/stage1-validate.d.ts.map +1 -0
- package/dist/pipeline/stage1-validate.js +69 -0
- package/dist/pipeline/stage1-validate.js.map +1 -0
- package/dist/pipeline/stage2-auth.d.ts +12 -0
- package/dist/pipeline/stage2-auth.d.ts.map +1 -0
- package/dist/pipeline/stage2-auth.js +18 -0
- package/dist/pipeline/stage2-auth.js.map +1 -0
- package/dist/pipeline/stage3-policy.d.ts +26 -0
- package/dist/pipeline/stage3-policy.d.ts.map +1 -0
- package/dist/pipeline/stage3-policy.js +384 -0
- package/dist/pipeline/stage3-policy.js.map +1 -0
- package/dist/pipeline/stage4-wait.d.ts +8 -0
- package/dist/pipeline/stage4-wait.d.ts.map +1 -0
- package/dist/pipeline/stage4-wait.js +87 -0
- package/dist/pipeline/stage4-wait.js.map +1 -0
- package/dist/pipeline/stage5-execute.d.ts +120 -0
- package/dist/pipeline/stage5-execute.d.ts.map +1 -0
- package/dist/pipeline/stage5-execute.js +1070 -0
- package/dist/pipeline/stage5-execute.js.map +1 -0
- package/dist/pipeline/stage6-confirm.d.ts +11 -0
- package/dist/pipeline/stage6-confirm.d.ts.map +1 -0
- package/dist/pipeline/stage6-confirm.js +110 -0
- package/dist/pipeline/stage6-confirm.js.map +1 -0
- package/dist/pipeline/stages.d.ts +11 -245
- package/dist/pipeline/stages.d.ts.map +1 -1
- package/dist/pipeline/stages.js +11 -1896
- package/dist/pipeline/stages.js.map +1 -1
- package/dist/rpc-proxy/sync-pipeline.js +2 -2
- package/dist/rpc-proxy/sync-pipeline.js.map +1 -1
- package/dist/services/autostop/autostop-service.d.ts +4 -1
- package/dist/services/autostop/autostop-service.d.ts.map +1 -1
- package/dist/services/autostop/autostop-service.js +27 -7
- package/dist/services/autostop/autostop-service.js.map +1 -1
- package/dist/services/defi/position-tracker.d.ts +5 -0
- package/dist/services/defi/position-tracker.d.ts.map +1 -1
- package/dist/services/defi/position-tracker.js +41 -6
- package/dist/services/defi/position-tracker.js.map +1 -1
- package/dist/services/defi/position-write-queue.d.ts.map +1 -1
- package/dist/services/defi/position-write-queue.js +3 -2
- package/dist/services/defi/position-write-queue.js.map +1 -1
- package/dist/services/incoming/__tests__/integration-wiring.test.js +58 -0
- package/dist/services/incoming/__tests__/integration-wiring.test.js.map +1 -1
- package/dist/services/incoming/incoming-tx-monitor-service.d.ts.map +1 -1
- package/dist/services/incoming/incoming-tx-monitor-service.js +11 -14
- package/dist/services/incoming/incoming-tx-monitor-service.js.map +1 -1
- package/dist/services/incoming/incoming-tx-workers.d.ts +2 -2
- package/dist/services/incoming/incoming-tx-workers.d.ts.map +1 -1
- package/dist/services/incoming/incoming-tx-workers.js +1 -1
- package/dist/services/incoming/incoming-tx-workers.js.map +1 -1
- package/dist/services/incoming/safety-rules.d.ts.map +1 -1
- package/dist/services/incoming/safety-rules.js +3 -2
- package/dist/services/incoming/safety-rules.js.map +1 -1
- package/dist/services/incoming/subscription-multiplexer.d.ts +2 -6
- package/dist/services/incoming/subscription-multiplexer.d.ts.map +1 -1
- package/dist/services/incoming/subscription-multiplexer.js +1 -3
- package/dist/services/incoming/subscription-multiplexer.js.map +1 -1
- package/dist/services/monitoring/balance-monitor-service.d.ts.map +1 -1
- package/dist/services/monitoring/balance-monitor-service.js +2 -2
- package/dist/services/monitoring/balance-monitor-service.js.map +1 -1
- package/dist/services/signing-sdk/approval-channel-router.d.ts +7 -7
- package/dist/services/signing-sdk/approval-channel-router.d.ts.map +1 -1
- package/dist/services/signing-sdk/approval-channel-router.js +13 -13
- package/dist/services/signing-sdk/approval-channel-router.js.map +1 -1
- package/dist/services/signing-sdk/channels/index.d.ts +2 -2
- package/dist/services/signing-sdk/channels/index.d.ts.map +1 -1
- package/dist/services/signing-sdk/channels/index.js +1 -1
- package/dist/services/signing-sdk/channels/index.js.map +1 -1
- package/dist/services/signing-sdk/channels/push-relay-signing-channel.d.ts +59 -0
- package/dist/services/signing-sdk/channels/push-relay-signing-channel.d.ts.map +1 -0
- package/dist/services/signing-sdk/channels/push-relay-signing-channel.js +190 -0
- package/dist/services/signing-sdk/channels/push-relay-signing-channel.js.map +1 -0
- package/dist/services/signing-sdk/channels/telegram-signing-channel.d.ts +1 -1
- package/dist/services/signing-sdk/channels/telegram-signing-channel.js +1 -1
- package/dist/services/signing-sdk/channels/wallet-notification-channel.d.ts +6 -7
- package/dist/services/signing-sdk/channels/wallet-notification-channel.d.ts.map +1 -1
- package/dist/services/signing-sdk/channels/wallet-notification-channel.js +38 -55
- package/dist/services/signing-sdk/channels/wallet-notification-channel.js.map +1 -1
- package/dist/services/signing-sdk/index.d.ts +3 -3
- package/dist/services/signing-sdk/index.d.ts.map +1 -1
- package/dist/services/signing-sdk/index.js +2 -2
- package/dist/services/signing-sdk/index.js.map +1 -1
- package/dist/services/signing-sdk/preset-auto-setup.js +2 -2
- package/dist/services/signing-sdk/preset-auto-setup.js.map +1 -1
- package/dist/services/signing-sdk/sign-request-builder.d.ts +2 -2
- package/dist/services/signing-sdk/sign-request-builder.d.ts.map +1 -1
- package/dist/services/signing-sdk/sign-request-builder.js +17 -25
- package/dist/services/signing-sdk/sign-request-builder.js.map +1 -1
- package/dist/services/signing-sdk/wallet-app-service.d.ts +4 -0
- package/dist/services/signing-sdk/wallet-app-service.d.ts.map +1 -1
- package/dist/services/signing-sdk/wallet-app-service.js +12 -5
- package/dist/services/signing-sdk/wallet-app-service.js.map +1 -1
- package/dist/services/staking/aggregate-staking-balance.d.ts +24 -0
- package/dist/services/staking/aggregate-staking-balance.d.ts.map +1 -0
- package/dist/services/staking/aggregate-staking-balance.js +82 -0
- package/dist/services/staking/aggregate-staking-balance.js.map +1 -0
- package/dist/services/wc-session-service.d.ts.map +1 -1
- package/dist/services/wc-session-service.js +2 -1
- package/dist/services/wc-session-service.js.map +1 -1
- package/dist/services/wc-signing-bridge.js +2 -2
- package/dist/services/wc-signing-bridge.js.map +1 -1
- package/dist/services/x402/payment-signer.d.ts.map +1 -1
- package/dist/services/x402/payment-signer.js +2 -5
- package/dist/services/x402/payment-signer.js.map +1 -1
- package/dist/services/x402/ssrf-guard.d.ts +4 -23
- package/dist/services/x402/ssrf-guard.d.ts.map +1 -1
- package/dist/services/x402/ssrf-guard.js +3 -232
- package/dist/services/x402/ssrf-guard.js.map +1 -1
- package/dist/signing/capabilities/eip712-signer.d.ts.map +1 -1
- package/dist/signing/capabilities/eip712-signer.js +2 -0
- package/dist/signing/capabilities/eip712-signer.js.map +1 -1
- package/package.json +5 -5
- package/public/admin/assets/index-CpFF2lCo.js +3 -0
- package/public/admin/index.html +1 -1
- package/dist/notifications/channels/ntfy.d.ts +0 -13
- package/dist/notifications/channels/ntfy.d.ts.map +0 -1
- package/dist/notifications/channels/ntfy.js +0 -74
- package/dist/notifications/channels/ntfy.js.map +0 -1
- package/dist/services/signing-sdk/channels/ntfy-signing-channel.d.ts +0 -66
- package/dist/services/signing-sdk/channels/ntfy-signing-channel.d.ts.map +0 -1
- package/dist/services/signing-sdk/channels/ntfy-signing-channel.js +0 -270
- package/dist/services/signing-sdk/channels/ntfy-signing-channel.js.map +0 -1
- package/public/admin/assets/index-CQ3i4P2U.js +0 -3
|
@@ -0,0 +1,1070 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stage 5: On-chain execution (build -> simulate -> sign -> submit).
|
|
3
|
+
*
|
|
4
|
+
* Contains:
|
|
5
|
+
* - buildByType: route to correct adapter method based on request.type
|
|
6
|
+
* - ERC721/ERC1155 UserOp ABI constants
|
|
7
|
+
* - buildUserOpCalls: convert request to viem calls[] for UserOperation
|
|
8
|
+
* - stage5ExecuteSmartAccount: smart account UserOperation pipeline
|
|
9
|
+
* - stage5Execute: main EOA execution with CONC-01 retry logic
|
|
10
|
+
*
|
|
11
|
+
* @see docs/32-pipeline-design.md
|
|
12
|
+
*/
|
|
13
|
+
import { eq } from 'drizzle-orm';
|
|
14
|
+
import { WAIaaSError, ChainError, } from '@waiaas/core';
|
|
15
|
+
import { wallets, transactions } from '../infrastructure/database/schema.js';
|
|
16
|
+
import { insertAuditLog } from '../infrastructure/database/audit-helper.js';
|
|
17
|
+
import { GAS_SAFETY_NUMERATOR, GAS_SAFETY_DENOMINATOR } from '../constants.js';
|
|
18
|
+
import { sleep } from './sleep.js';
|
|
19
|
+
// v30.6: ERC-4337 smart account imports
|
|
20
|
+
import { privateKeyToAccount } from 'viem/accounts';
|
|
21
|
+
import { createPublicClient, http, encodeFunctionData, toHex } from 'viem';
|
|
22
|
+
import { SmartAccountService, SOLADY_FACTORY_ADDRESS } from '../infrastructure/smart-account/smart-account-service.js';
|
|
23
|
+
import { createSmartAccountBundlerClient } from '../infrastructure/smart-account/smart-account-clients.js';
|
|
24
|
+
import { decryptProviderApiKey } from '../infrastructure/smart-account/aa-provider-crypto.js';
|
|
25
|
+
import { getRequestAmount, getRequestTo, getRequestMemo, resolveNotificationTo, formatNotificationAmount, resolveDisplayAmount, } from './pipeline-helpers.js';
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Helper: buildByType -- route to correct adapter method based on request.type
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
/**
|
|
30
|
+
* Build unsigned transaction by dispatching to the correct IChainAdapter method
|
|
31
|
+
* based on request.type (TRANSFER/TOKEN_TRANSFER/CONTRACT_CALL/APPROVE/BATCH).
|
|
32
|
+
*/
|
|
33
|
+
export async function buildByType(adapter, request, walletPublicKey) {
|
|
34
|
+
const type = ('type' in request && request.type) || 'TRANSFER';
|
|
35
|
+
switch (type) {
|
|
36
|
+
case 'TRANSFER': {
|
|
37
|
+
return adapter.buildTransaction({
|
|
38
|
+
from: walletPublicKey,
|
|
39
|
+
to: getRequestTo(request),
|
|
40
|
+
amount: BigInt(getRequestAmount(request)),
|
|
41
|
+
memo: getRequestMemo(request),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
case 'TOKEN_TRANSFER': {
|
|
45
|
+
const req = request;
|
|
46
|
+
return adapter.buildTokenTransfer({
|
|
47
|
+
from: walletPublicKey,
|
|
48
|
+
to: req.to,
|
|
49
|
+
amount: BigInt(req.amount),
|
|
50
|
+
token: req.token,
|
|
51
|
+
memo: req.memo,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
case 'CONTRACT_CALL': {
|
|
55
|
+
const req = request;
|
|
56
|
+
return adapter.buildContractCall({
|
|
57
|
+
from: walletPublicKey,
|
|
58
|
+
to: req.to,
|
|
59
|
+
calldata: req.calldata,
|
|
60
|
+
abi: req.abi,
|
|
61
|
+
value: req.value ? BigInt(req.value) : undefined,
|
|
62
|
+
programId: req.programId,
|
|
63
|
+
instructionData: req.instructionData
|
|
64
|
+
? Buffer.from(req.instructionData, 'base64')
|
|
65
|
+
: undefined,
|
|
66
|
+
accounts: req.accounts,
|
|
67
|
+
// Pass through preInstructions for Solana (e.g., ATA creation for Jito staking)
|
|
68
|
+
preInstructions: req.preInstructions?.map((pre) => ({
|
|
69
|
+
programId: pre.programId,
|
|
70
|
+
data: Buffer.from(pre.data, 'base64'),
|
|
71
|
+
accounts: pre.accounts,
|
|
72
|
+
})),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
case 'APPROVE': {
|
|
76
|
+
const req = request;
|
|
77
|
+
// v31.0: NFT approval routing
|
|
78
|
+
if (req.nft) {
|
|
79
|
+
const approvalType = req.amount === '0' ? 'single' : 'all';
|
|
80
|
+
return adapter.approveNft({
|
|
81
|
+
from: walletPublicKey,
|
|
82
|
+
spender: req.spender,
|
|
83
|
+
token: {
|
|
84
|
+
address: req.token.address,
|
|
85
|
+
tokenId: req.nft.tokenId,
|
|
86
|
+
standard: req.nft.standard,
|
|
87
|
+
},
|
|
88
|
+
approvalType,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return adapter.buildApprove({
|
|
92
|
+
from: walletPublicKey,
|
|
93
|
+
spender: req.spender,
|
|
94
|
+
token: req.token,
|
|
95
|
+
amount: BigInt(req.amount),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
case 'NFT_TRANSFER': {
|
|
99
|
+
const req = request;
|
|
100
|
+
return adapter.buildNftTransferTx({
|
|
101
|
+
from: walletPublicKey,
|
|
102
|
+
to: req.to,
|
|
103
|
+
token: {
|
|
104
|
+
address: req.token.address,
|
|
105
|
+
tokenId: req.token.tokenId,
|
|
106
|
+
standard: req.token.standard,
|
|
107
|
+
},
|
|
108
|
+
amount: BigInt(req.amount ?? '1'),
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
case 'CONTRACT_DEPLOY': {
|
|
112
|
+
const req = request;
|
|
113
|
+
// Contract deployment: to=undefined, data=bytecode(+constructorArgs)
|
|
114
|
+
const deployData = req.constructorArgs
|
|
115
|
+
? req.bytecode + req.constructorArgs.replace(/^0x/, '')
|
|
116
|
+
: req.bytecode;
|
|
117
|
+
return adapter.buildContractCall({
|
|
118
|
+
from: walletPublicKey,
|
|
119
|
+
to: '', // adapter handles to='' as to=undefined for deploy
|
|
120
|
+
calldata: deployData,
|
|
121
|
+
value: req.value ? BigInt(req.value) : undefined,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
case 'BATCH': {
|
|
125
|
+
const req = request;
|
|
126
|
+
return adapter.buildBatch({
|
|
127
|
+
from: walletPublicKey,
|
|
128
|
+
instructions: req.instructions.map((instr) => {
|
|
129
|
+
// Classify by field presence (same logic as classifyInstruction in Phase 80)
|
|
130
|
+
if ('spender' in instr) {
|
|
131
|
+
const a = instr;
|
|
132
|
+
return {
|
|
133
|
+
from: walletPublicKey,
|
|
134
|
+
spender: a.spender,
|
|
135
|
+
token: a.token,
|
|
136
|
+
amount: BigInt(a.amount),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
if ('token' in instr) {
|
|
140
|
+
const t = instr;
|
|
141
|
+
return {
|
|
142
|
+
from: walletPublicKey,
|
|
143
|
+
to: t.to,
|
|
144
|
+
amount: BigInt(t.amount),
|
|
145
|
+
token: t.token,
|
|
146
|
+
memo: t.memo,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
if ('programId' in instr || 'calldata' in instr) {
|
|
150
|
+
const c = instr;
|
|
151
|
+
return {
|
|
152
|
+
from: walletPublicKey,
|
|
153
|
+
to: c.to,
|
|
154
|
+
calldata: c.calldata,
|
|
155
|
+
programId: c.programId,
|
|
156
|
+
instructionData: c.instructionData
|
|
157
|
+
? Buffer.from(c.instructionData, 'base64')
|
|
158
|
+
: undefined,
|
|
159
|
+
accounts: c.accounts,
|
|
160
|
+
value: c.value ? BigInt(c.value) : undefined,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
// Default: TRANSFER instruction
|
|
164
|
+
const tr = instr;
|
|
165
|
+
return {
|
|
166
|
+
from: walletPublicKey,
|
|
167
|
+
to: tr.to,
|
|
168
|
+
amount: BigInt(tr.amount),
|
|
169
|
+
memo: tr.memo,
|
|
170
|
+
};
|
|
171
|
+
}),
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
default:
|
|
175
|
+
throw new WAIaaSError('CHAIN_ERROR', {
|
|
176
|
+
message: `Unknown transaction type: ${type}`,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
// Stage 5: Smart account ERC-4337 UserOperation helpers
|
|
182
|
+
// ---------------------------------------------------------------------------
|
|
183
|
+
/**
|
|
184
|
+
* Minimal ERC-20 ABI for transfer/approve encoding in UserOperation calls.
|
|
185
|
+
* Inline to avoid cross-package import from @waiaas/adapters-evm.
|
|
186
|
+
*/
|
|
187
|
+
const ERC20_USEROP_ABI = [
|
|
188
|
+
{ type: 'function', name: 'transfer', inputs: [{ name: 'to', type: 'address' }, { name: 'amount', type: 'uint256' }], outputs: [{ type: 'bool' }] },
|
|
189
|
+
{ type: 'function', name: 'approve', inputs: [{ name: 'spender', type: 'address' }, { name: 'amount', type: 'uint256' }], outputs: [{ type: 'bool' }] },
|
|
190
|
+
];
|
|
191
|
+
/** ERC-721 ABI for NFT UserOp calls (safeTransferFrom, approve, setApprovalForAll). */
|
|
192
|
+
export const ERC721_USEROP_ABI = [
|
|
193
|
+
{ type: 'function', name: 'safeTransferFrom', inputs: [
|
|
194
|
+
{ name: 'from', type: 'address' }, { name: 'to', type: 'address' }, { name: 'tokenId', type: 'uint256' },
|
|
195
|
+
], outputs: [] },
|
|
196
|
+
{ type: 'function', name: 'approve', inputs: [
|
|
197
|
+
{ name: 'to', type: 'address' }, { name: 'tokenId', type: 'uint256' },
|
|
198
|
+
], outputs: [] },
|
|
199
|
+
{ type: 'function', name: 'setApprovalForAll', inputs: [
|
|
200
|
+
{ name: 'operator', type: 'address' }, { name: 'approved', type: 'bool' },
|
|
201
|
+
], outputs: [] },
|
|
202
|
+
];
|
|
203
|
+
/** ERC-1155 ABI for NFT UserOp calls (safeTransferFrom, setApprovalForAll). */
|
|
204
|
+
export const ERC1155_USEROP_ABI = [
|
|
205
|
+
{ type: 'function', name: 'safeTransferFrom', inputs: [
|
|
206
|
+
{ name: 'from', type: 'address' }, { name: 'to', type: 'address' },
|
|
207
|
+
{ name: 'id', type: 'uint256' }, { name: 'amount', type: 'uint256' }, { name: 'data', type: 'bytes' },
|
|
208
|
+
], outputs: [] },
|
|
209
|
+
{ type: 'function', name: 'setApprovalForAll', inputs: [
|
|
210
|
+
{ name: 'operator', type: 'address' }, { name: 'approved', type: 'bool' },
|
|
211
|
+
], outputs: [] },
|
|
212
|
+
];
|
|
213
|
+
/**
|
|
214
|
+
* Convert a TransactionRequest to viem's calls[] format for UserOperation submission.
|
|
215
|
+
* Each call is { to, value, data } for the smart account to execute.
|
|
216
|
+
*
|
|
217
|
+
* @param walletAddress - Smart account address (required for NFT_TRANSFER safeTransferFrom 'from' param)
|
|
218
|
+
*/
|
|
219
|
+
export function buildUserOpCalls(request, walletAddress) {
|
|
220
|
+
const type = ('type' in request && request.type) || 'TRANSFER';
|
|
221
|
+
switch (type) {
|
|
222
|
+
case 'TRANSFER': {
|
|
223
|
+
return [{
|
|
224
|
+
to: getRequestTo(request),
|
|
225
|
+
value: BigInt(getRequestAmount(request)),
|
|
226
|
+
data: '0x',
|
|
227
|
+
}];
|
|
228
|
+
}
|
|
229
|
+
case 'TOKEN_TRANSFER': {
|
|
230
|
+
const req = request;
|
|
231
|
+
return [{
|
|
232
|
+
to: req.token.address,
|
|
233
|
+
value: 0n,
|
|
234
|
+
data: encodeFunctionData({
|
|
235
|
+
abi: ERC20_USEROP_ABI,
|
|
236
|
+
functionName: 'transfer',
|
|
237
|
+
args: [req.to, BigInt(req.amount)],
|
|
238
|
+
}),
|
|
239
|
+
}];
|
|
240
|
+
}
|
|
241
|
+
case 'CONTRACT_CALL': {
|
|
242
|
+
const req = request;
|
|
243
|
+
return [{
|
|
244
|
+
to: req.to,
|
|
245
|
+
value: BigInt(req.value ?? '0'),
|
|
246
|
+
data: (req.calldata || '0x'),
|
|
247
|
+
}];
|
|
248
|
+
}
|
|
249
|
+
case 'APPROVE': {
|
|
250
|
+
const req = request;
|
|
251
|
+
// v31.0: NFT approval routing for Smart Account
|
|
252
|
+
if (req.nft) {
|
|
253
|
+
const approvalType = req.amount === '0' ? 'single' : 'all';
|
|
254
|
+
if (req.nft.standard === 'METAPLEX') {
|
|
255
|
+
throw new WAIaaSError('CHAIN_ERROR', {
|
|
256
|
+
message: 'Smart Account (ERC-4337) does not support Solana METAPLEX NFT approvals',
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
if (approvalType === 'single' && req.nft.standard === 'ERC-721') {
|
|
260
|
+
return [{
|
|
261
|
+
to: req.token.address,
|
|
262
|
+
value: 0n,
|
|
263
|
+
data: encodeFunctionData({
|
|
264
|
+
abi: ERC721_USEROP_ABI,
|
|
265
|
+
functionName: 'approve',
|
|
266
|
+
args: [req.spender, BigInt(req.nft.tokenId)],
|
|
267
|
+
}),
|
|
268
|
+
}];
|
|
269
|
+
}
|
|
270
|
+
// setApprovalForAll (ERC-721 all / ERC-1155 all)
|
|
271
|
+
const nftAbi = req.nft.standard === 'ERC-721' ? ERC721_USEROP_ABI : ERC1155_USEROP_ABI;
|
|
272
|
+
return [{
|
|
273
|
+
to: req.token.address,
|
|
274
|
+
value: 0n,
|
|
275
|
+
data: encodeFunctionData({
|
|
276
|
+
abi: nftAbi,
|
|
277
|
+
functionName: 'setApprovalForAll',
|
|
278
|
+
args: [req.spender, true],
|
|
279
|
+
}),
|
|
280
|
+
}];
|
|
281
|
+
}
|
|
282
|
+
return [{
|
|
283
|
+
to: req.token.address,
|
|
284
|
+
value: 0n,
|
|
285
|
+
data: encodeFunctionData({
|
|
286
|
+
abi: ERC20_USEROP_ABI,
|
|
287
|
+
functionName: 'approve',
|
|
288
|
+
args: [req.spender, BigInt(req.amount)],
|
|
289
|
+
}),
|
|
290
|
+
}];
|
|
291
|
+
}
|
|
292
|
+
case 'BATCH': {
|
|
293
|
+
const req = request;
|
|
294
|
+
return req.instructions.map((instr) => {
|
|
295
|
+
if ('spender' in instr) {
|
|
296
|
+
// APPROVE instruction
|
|
297
|
+
const a = instr;
|
|
298
|
+
return {
|
|
299
|
+
to: a.token.address,
|
|
300
|
+
value: 0n,
|
|
301
|
+
data: encodeFunctionData({
|
|
302
|
+
abi: ERC20_USEROP_ABI,
|
|
303
|
+
functionName: 'approve',
|
|
304
|
+
args: [a.spender, BigInt(a.amount)],
|
|
305
|
+
}),
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
if ('token' in instr) {
|
|
309
|
+
// TOKEN_TRANSFER instruction
|
|
310
|
+
const t = instr;
|
|
311
|
+
return {
|
|
312
|
+
to: t.token.address,
|
|
313
|
+
value: 0n,
|
|
314
|
+
data: encodeFunctionData({
|
|
315
|
+
abi: ERC20_USEROP_ABI,
|
|
316
|
+
functionName: 'transfer',
|
|
317
|
+
args: [t.to, BigInt(t.amount)],
|
|
318
|
+
}),
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
if ('calldata' in instr) {
|
|
322
|
+
// CONTRACT_CALL instruction (also used by ActionProvider resolve() output)
|
|
323
|
+
const c = instr;
|
|
324
|
+
return {
|
|
325
|
+
to: c.to,
|
|
326
|
+
value: BigInt(c.value ?? '0'),
|
|
327
|
+
data: (c.calldata || '0x'),
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
// TRANSFER instruction (native transfer)
|
|
331
|
+
const t = instr;
|
|
332
|
+
return {
|
|
333
|
+
to: t.to,
|
|
334
|
+
value: BigInt(t.amount),
|
|
335
|
+
data: '0x',
|
|
336
|
+
};
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
case 'NFT_TRANSFER': {
|
|
340
|
+
const req = request;
|
|
341
|
+
if (req.token.standard === 'METAPLEX') {
|
|
342
|
+
throw new WAIaaSError('CHAIN_ERROR', {
|
|
343
|
+
message: 'Smart Account (ERC-4337) does not support Solana METAPLEX NFT transfers',
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
const from = (walletAddress ?? '0x0000000000000000000000000000000000000000');
|
|
347
|
+
if (req.token.standard === 'ERC-721') {
|
|
348
|
+
return [{
|
|
349
|
+
to: req.token.address,
|
|
350
|
+
value: 0n,
|
|
351
|
+
data: encodeFunctionData({
|
|
352
|
+
abi: ERC721_USEROP_ABI,
|
|
353
|
+
functionName: 'safeTransferFrom',
|
|
354
|
+
args: [from, req.to, BigInt(req.token.tokenId)],
|
|
355
|
+
}),
|
|
356
|
+
}];
|
|
357
|
+
}
|
|
358
|
+
// ERC-1155
|
|
359
|
+
return [{
|
|
360
|
+
to: req.token.address,
|
|
361
|
+
value: 0n,
|
|
362
|
+
data: encodeFunctionData({
|
|
363
|
+
abi: ERC1155_USEROP_ABI,
|
|
364
|
+
functionName: 'safeTransferFrom',
|
|
365
|
+
args: [from, req.to, BigInt(req.token.tokenId), BigInt(req.amount ?? '1'), '0x'],
|
|
366
|
+
}),
|
|
367
|
+
}];
|
|
368
|
+
}
|
|
369
|
+
case 'CONTRACT_DEPLOY': {
|
|
370
|
+
const req = request;
|
|
371
|
+
const deployData = req.constructorArgs
|
|
372
|
+
? req.bytecode + req.constructorArgs.replace(/^0x/, '')
|
|
373
|
+
: req.bytecode;
|
|
374
|
+
// Smart account contract deployment via CREATE2-like pattern
|
|
375
|
+
// to is empty (factory handles deployment), data is full bytecode+args
|
|
376
|
+
return [{
|
|
377
|
+
to: '0x', // will be interpreted as factory/self call
|
|
378
|
+
value: BigInt(req.value ?? '0'),
|
|
379
|
+
data: deployData,
|
|
380
|
+
}];
|
|
381
|
+
}
|
|
382
|
+
default:
|
|
383
|
+
throw new WAIaaSError('CHAIN_ERROR', {
|
|
384
|
+
message: `Unknown transaction type for UserOp: ${type}`,
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Stage 5 smart account path: execute via UserOperation through BundlerClient.
|
|
390
|
+
*
|
|
391
|
+
* Flow:
|
|
392
|
+
* 1. Decrypt signer key -> create LocalAccount via viem's privateKeyToAccount
|
|
393
|
+
* 2. Create SmartAccount instance via SmartAccountService
|
|
394
|
+
* 3. Create BundlerClient via createSmartAccountBundlerClient
|
|
395
|
+
* 4. Build calls[] from request via buildUserOpCalls
|
|
396
|
+
* 5. prepareUserOperation -> apply 120% gas safety margin
|
|
397
|
+
* 6. sendUserOperation -> waitForUserOperationReceipt
|
|
398
|
+
* 7. Update DB: SUBMITTED -> CONFIRMED, update deployed status if needed
|
|
399
|
+
*
|
|
400
|
+
* Error mapping:
|
|
401
|
+
* - Paymaster rejection (message contains 'paymaster'/'PM_') -> PAYMASTER_REJECTED
|
|
402
|
+
* - UserOperationReverted -> TRANSACTION_REVERTED
|
|
403
|
+
* - Receipt timeout -> TRANSACTION_TIMEOUT
|
|
404
|
+
* - Other -> CHAIN_ERROR
|
|
405
|
+
*/
|
|
406
|
+
async function stage5ExecuteSmartAccount(ctx) {
|
|
407
|
+
// Check for deprecated Solady factory before proceeding
|
|
408
|
+
if (ctx.wallet.factoryAddress?.toLowerCase() === SOLADY_FACTORY_ADDRESS.toLowerCase()) {
|
|
409
|
+
throw new WAIaaSError('DEPRECATED_SMART_ACCOUNT');
|
|
410
|
+
}
|
|
411
|
+
const reqAmount = formatNotificationAmount(ctx.request, ctx.wallet.chain);
|
|
412
|
+
const displayAmount = await resolveDisplayAmount(ctx.amountUsd ?? null, ctx.settingsService, ctx.forexRateService);
|
|
413
|
+
// Build calls[] from request (pass wallet address for NFT safeTransferFrom 'from' param)
|
|
414
|
+
const calls = buildUserOpCalls(ctx.request, ctx.wallet.publicKey);
|
|
415
|
+
// CRITICAL: key MUST be released in finally block
|
|
416
|
+
let privateKey = null;
|
|
417
|
+
try {
|
|
418
|
+
// Step 1: Decrypt signer key
|
|
419
|
+
privateKey = await ctx.keyStore.decryptPrivateKey(ctx.walletId, ctx.masterPassword);
|
|
420
|
+
const hexKey = toHex(privateKey);
|
|
421
|
+
const localAccount = privateKeyToAccount(hexKey);
|
|
422
|
+
// Step 2: Create SmartAccount via SmartAccountService
|
|
423
|
+
const smartAccountService = new SmartAccountService();
|
|
424
|
+
// #251: Resolve viem Chain from EVM_CHAIN_MAP using network ID
|
|
425
|
+
const { EVM_CHAIN_MAP } = await import('@waiaas/adapter-evm');
|
|
426
|
+
const chainEntry = EVM_CHAIN_MAP[ctx.resolvedNetwork];
|
|
427
|
+
const publicClient = createPublicClient({
|
|
428
|
+
chain: chainEntry?.viemChain,
|
|
429
|
+
transport: http(ctx.resolvedRpcUrl),
|
|
430
|
+
});
|
|
431
|
+
const smartAccountInfo = await smartAccountService.createSmartAccount({
|
|
432
|
+
owner: localAccount,
|
|
433
|
+
client: publicClient,
|
|
434
|
+
});
|
|
435
|
+
// Step 3: Create BundlerClient from wallet's provider data (v30.9)
|
|
436
|
+
const decryptedApiKey = ctx.wallet.aaProviderApiKeyEncrypted
|
|
437
|
+
? decryptProviderApiKey(ctx.wallet.aaProviderApiKeyEncrypted, ctx.masterPassword)
|
|
438
|
+
: null;
|
|
439
|
+
const walletProvider = {
|
|
440
|
+
aaProvider: ctx.wallet.aaProvider ?? null,
|
|
441
|
+
aaProviderApiKey: decryptedApiKey,
|
|
442
|
+
aaBundlerUrl: ctx.wallet.aaBundlerUrl ?? null,
|
|
443
|
+
aaPaymasterUrl: ctx.wallet.aaPaymasterUrl ?? null,
|
|
444
|
+
aaPaymasterPolicyId: ctx.wallet.aaPaymasterPolicyId ?? null,
|
|
445
|
+
};
|
|
446
|
+
const bundlerClient = createSmartAccountBundlerClient({
|
|
447
|
+
client: publicClient,
|
|
448
|
+
account: smartAccountInfo.account,
|
|
449
|
+
networkId: ctx.resolvedNetwork,
|
|
450
|
+
walletProvider,
|
|
451
|
+
settingsService: ctx.settingsService,
|
|
452
|
+
});
|
|
453
|
+
// Step 4: Prepare UserOperation to get gas estimates
|
|
454
|
+
const prepared = await bundlerClient.prepareUserOperation({ calls });
|
|
455
|
+
// Step 5: Apply 120% gas safety margin per CLAUDE.md rule
|
|
456
|
+
const safeCallGasLimit = (BigInt(prepared.callGasLimit) * GAS_SAFETY_NUMERATOR) / GAS_SAFETY_DENOMINATOR;
|
|
457
|
+
const safeVerificationGasLimit = (BigInt(prepared.verificationGasLimit) * GAS_SAFETY_NUMERATOR) / GAS_SAFETY_DENOMINATOR;
|
|
458
|
+
const safePreVerificationGas = (BigInt(prepared.preVerificationGas) * GAS_SAFETY_NUMERATOR) / GAS_SAFETY_DENOMINATOR;
|
|
459
|
+
// Step 6: Submit UserOperation with overridden gas limits
|
|
460
|
+
ctx.metricsCounter?.increment('rpc.calls', { network: ctx.resolvedNetwork });
|
|
461
|
+
const userOpHash = await bundlerClient.sendUserOperation({
|
|
462
|
+
calls,
|
|
463
|
+
userOperation: {
|
|
464
|
+
callGasLimit: safeCallGasLimit,
|
|
465
|
+
verificationGasLimit: safeVerificationGasLimit,
|
|
466
|
+
preVerificationGas: safePreVerificationGas,
|
|
467
|
+
},
|
|
468
|
+
});
|
|
469
|
+
ctx.metricsCounter?.increment('tx.submitted', { network: ctx.resolvedNetwork });
|
|
470
|
+
// Update DB: SUBMITTED with userOpHash
|
|
471
|
+
await ctx.db
|
|
472
|
+
.update(transactions)
|
|
473
|
+
.set({ status: 'SUBMITTED', txHash: userOpHash })
|
|
474
|
+
.where(eq(transactions.id, ctx.txId));
|
|
475
|
+
// Audit log: TX_SUBMITTED
|
|
476
|
+
if (ctx.sqlite) {
|
|
477
|
+
insertAuditLog(ctx.sqlite, {
|
|
478
|
+
eventType: 'TX_SUBMITTED',
|
|
479
|
+
actor: ctx.sessionId ?? 'system',
|
|
480
|
+
walletId: ctx.walletId,
|
|
481
|
+
txId: ctx.txId,
|
|
482
|
+
details: {
|
|
483
|
+
txHash: userOpHash,
|
|
484
|
+
chain: ctx.wallet.chain,
|
|
485
|
+
network: ctx.resolvedNetwork,
|
|
486
|
+
type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
|
|
487
|
+
accountType: 'smart',
|
|
488
|
+
},
|
|
489
|
+
severity: 'info',
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
// Notify TX_SUBMITTED
|
|
493
|
+
void ctx.notificationService?.notify('TX_SUBMITTED', ctx.walletId, {
|
|
494
|
+
txId: ctx.txId,
|
|
495
|
+
txHash: userOpHash,
|
|
496
|
+
amount: reqAmount,
|
|
497
|
+
to: resolveNotificationTo(ctx.request, ctx.resolvedNetwork, ctx.contractNameRegistry),
|
|
498
|
+
display_amount: displayAmount,
|
|
499
|
+
network: ctx.resolvedNetwork,
|
|
500
|
+
}, { txId: ctx.txId });
|
|
501
|
+
// Emit wallet:activity
|
|
502
|
+
ctx.eventBus?.emit('wallet:activity', {
|
|
503
|
+
walletId: ctx.walletId,
|
|
504
|
+
activity: 'TX_SUBMITTED',
|
|
505
|
+
details: { txId: ctx.txId, txHash: userOpHash },
|
|
506
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
507
|
+
});
|
|
508
|
+
// Step 7: Wait for UserOperation receipt (120s timeout)
|
|
509
|
+
const receipt = await bundlerClient.waitForUserOperationReceipt({
|
|
510
|
+
hash: userOpHash,
|
|
511
|
+
timeout: 120_000,
|
|
512
|
+
});
|
|
513
|
+
const txHash = receipt?.receipt?.transactionHash ?? userOpHash;
|
|
514
|
+
// Update DB: CONFIRMED with actual txHash
|
|
515
|
+
await ctx.db
|
|
516
|
+
.update(transactions)
|
|
517
|
+
.set({ status: 'CONFIRMED', txHash })
|
|
518
|
+
.where(eq(transactions.id, ctx.txId));
|
|
519
|
+
// Update deployed status if this was first UserOp (lazy deployment)
|
|
520
|
+
const walletRow = ctx.db.select().from(wallets).where(eq(wallets.id, ctx.walletId)).get();
|
|
521
|
+
if (walletRow && !walletRow.deployed) {
|
|
522
|
+
ctx.db.update(wallets).set({ deployed: true }).where(eq(wallets.id, ctx.walletId)).run();
|
|
523
|
+
}
|
|
524
|
+
ctx.metricsCounter?.increment('tx.confirmed', { network: ctx.resolvedNetwork });
|
|
525
|
+
// Store submitResult for Stage 6
|
|
526
|
+
ctx.submitResult = { txHash, status: 'confirmed' };
|
|
527
|
+
// Audit log: TX_CONFIRMED
|
|
528
|
+
if (ctx.sqlite) {
|
|
529
|
+
insertAuditLog(ctx.sqlite, {
|
|
530
|
+
eventType: 'TX_CONFIRMED',
|
|
531
|
+
actor: ctx.sessionId ?? 'system',
|
|
532
|
+
walletId: ctx.walletId,
|
|
533
|
+
txId: ctx.txId,
|
|
534
|
+
details: {
|
|
535
|
+
txHash,
|
|
536
|
+
chain: ctx.wallet.chain,
|
|
537
|
+
network: ctx.resolvedNetwork,
|
|
538
|
+
accountType: 'smart',
|
|
539
|
+
},
|
|
540
|
+
severity: 'info',
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
// Notify TX_CONFIRMED
|
|
544
|
+
void ctx.notificationService?.notify('TX_CONFIRMED', ctx.walletId, {
|
|
545
|
+
txId: ctx.txId,
|
|
546
|
+
txHash,
|
|
547
|
+
amount: reqAmount,
|
|
548
|
+
to: resolveNotificationTo(ctx.request, ctx.resolvedNetwork, ctx.contractNameRegistry),
|
|
549
|
+
display_amount: displayAmount,
|
|
550
|
+
network: ctx.resolvedNetwork,
|
|
551
|
+
}, { txId: ctx.txId });
|
|
552
|
+
// Emit transaction:completed event
|
|
553
|
+
ctx.eventBus?.emit('transaction:completed', {
|
|
554
|
+
walletId: ctx.walletId,
|
|
555
|
+
txId: ctx.txId,
|
|
556
|
+
txHash,
|
|
557
|
+
network: ctx.resolvedNetwork,
|
|
558
|
+
type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
|
|
559
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
catch (err) {
|
|
563
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
564
|
+
const errName = err instanceof Error ? err.name : '';
|
|
565
|
+
// Already a WAIaaSError? (e.g., CHAIN_ERROR from bundler URL not configured)
|
|
566
|
+
if (err instanceof WAIaaSError) {
|
|
567
|
+
// Update DB to FAILED
|
|
568
|
+
await ctx.db
|
|
569
|
+
.update(transactions)
|
|
570
|
+
.set({ status: 'FAILED', error: errMsg })
|
|
571
|
+
.where(eq(transactions.id, ctx.txId));
|
|
572
|
+
ctx.metricsCounter?.increment('tx.failed', { network: ctx.resolvedNetwork });
|
|
573
|
+
void ctx.notificationService?.notify('TX_FAILED', ctx.walletId, {
|
|
574
|
+
txId: ctx.txId,
|
|
575
|
+
error: errMsg,
|
|
576
|
+
amount: reqAmount,
|
|
577
|
+
display_amount: displayAmount,
|
|
578
|
+
network: ctx.resolvedNetwork,
|
|
579
|
+
}, { txId: ctx.txId });
|
|
580
|
+
ctx.eventBus?.emit('transaction:failed', {
|
|
581
|
+
walletId: ctx.walletId,
|
|
582
|
+
txId: ctx.txId,
|
|
583
|
+
error: errMsg,
|
|
584
|
+
network: ctx.resolvedNetwork,
|
|
585
|
+
type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
|
|
586
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
587
|
+
});
|
|
588
|
+
throw err;
|
|
589
|
+
}
|
|
590
|
+
// Paymaster rejection detection
|
|
591
|
+
if (errMsg.toLowerCase().includes('paymaster') ||
|
|
592
|
+
errMsg.includes('PM_') ||
|
|
593
|
+
errName.includes('Paymaster')) {
|
|
594
|
+
await ctx.db
|
|
595
|
+
.update(transactions)
|
|
596
|
+
.set({ status: 'FAILED', error: `Paymaster rejected: ${errMsg}` })
|
|
597
|
+
.where(eq(transactions.id, ctx.txId));
|
|
598
|
+
ctx.metricsCounter?.increment('tx.failed', { network: ctx.resolvedNetwork });
|
|
599
|
+
if (ctx.sqlite) {
|
|
600
|
+
insertAuditLog(ctx.sqlite, {
|
|
601
|
+
eventType: 'TX_FAILED',
|
|
602
|
+
actor: ctx.sessionId ?? 'system',
|
|
603
|
+
walletId: ctx.walletId,
|
|
604
|
+
txId: ctx.txId,
|
|
605
|
+
details: { error: errMsg, stage: 5, reason: 'paymaster_rejected' },
|
|
606
|
+
severity: 'warning',
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
void ctx.notificationService?.notify('TX_FAILED', ctx.walletId, {
|
|
610
|
+
txId: ctx.txId,
|
|
611
|
+
error: `Paymaster rejected: ${errMsg}`,
|
|
612
|
+
amount: reqAmount,
|
|
613
|
+
display_amount: displayAmount,
|
|
614
|
+
network: ctx.resolvedNetwork,
|
|
615
|
+
}, { txId: ctx.txId });
|
|
616
|
+
ctx.eventBus?.emit('transaction:failed', {
|
|
617
|
+
walletId: ctx.walletId,
|
|
618
|
+
txId: ctx.txId,
|
|
619
|
+
error: `Paymaster rejected: ${errMsg}`,
|
|
620
|
+
network: ctx.resolvedNetwork,
|
|
621
|
+
type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
|
|
622
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
623
|
+
});
|
|
624
|
+
throw new WAIaaSError('PAYMASTER_REJECTED', {
|
|
625
|
+
message: `Paymaster rejected the UserOperation: ${errMsg}`,
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
// UserOperationReverted
|
|
629
|
+
if (errName === 'UserOperationReverted' || errMsg.includes('UserOperation reverted')) {
|
|
630
|
+
await ctx.db
|
|
631
|
+
.update(transactions)
|
|
632
|
+
.set({ status: 'FAILED', error: errMsg })
|
|
633
|
+
.where(eq(transactions.id, ctx.txId));
|
|
634
|
+
ctx.metricsCounter?.increment('tx.failed', { network: ctx.resolvedNetwork });
|
|
635
|
+
if (ctx.sqlite) {
|
|
636
|
+
insertAuditLog(ctx.sqlite, {
|
|
637
|
+
eventType: 'TX_FAILED',
|
|
638
|
+
actor: ctx.sessionId ?? 'system',
|
|
639
|
+
walletId: ctx.walletId,
|
|
640
|
+
txId: ctx.txId,
|
|
641
|
+
details: { error: errMsg, stage: 5, reason: 'user_op_reverted' },
|
|
642
|
+
severity: 'warning',
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
void ctx.notificationService?.notify('TX_FAILED', ctx.walletId, {
|
|
646
|
+
txId: ctx.txId,
|
|
647
|
+
error: errMsg,
|
|
648
|
+
amount: reqAmount,
|
|
649
|
+
display_amount: displayAmount,
|
|
650
|
+
network: ctx.resolvedNetwork,
|
|
651
|
+
}, { txId: ctx.txId });
|
|
652
|
+
ctx.eventBus?.emit('transaction:failed', {
|
|
653
|
+
walletId: ctx.walletId,
|
|
654
|
+
txId: ctx.txId,
|
|
655
|
+
error: errMsg,
|
|
656
|
+
network: ctx.resolvedNetwork,
|
|
657
|
+
type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
|
|
658
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
659
|
+
});
|
|
660
|
+
throw new WAIaaSError('TRANSACTION_REVERTED', {
|
|
661
|
+
message: errMsg,
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
// Receipt timeout
|
|
665
|
+
if (errName === 'WaitForUserOperationReceiptTimeoutError' || errMsg.includes('timed out')) {
|
|
666
|
+
await ctx.db
|
|
667
|
+
.update(transactions)
|
|
668
|
+
.set({ status: 'FAILED', error: `UserOp receipt timeout: ${errMsg}` })
|
|
669
|
+
.where(eq(transactions.id, ctx.txId));
|
|
670
|
+
ctx.metricsCounter?.increment('tx.failed', { network: ctx.resolvedNetwork });
|
|
671
|
+
if (ctx.sqlite) {
|
|
672
|
+
insertAuditLog(ctx.sqlite, {
|
|
673
|
+
eventType: 'TX_FAILED',
|
|
674
|
+
actor: ctx.sessionId ?? 'system',
|
|
675
|
+
walletId: ctx.walletId,
|
|
676
|
+
txId: ctx.txId,
|
|
677
|
+
details: { error: errMsg, stage: 5, reason: 'user_op_timeout' },
|
|
678
|
+
severity: 'warning',
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
void ctx.notificationService?.notify('TX_FAILED', ctx.walletId, {
|
|
682
|
+
txId: ctx.txId,
|
|
683
|
+
error: `Receipt timeout: ${errMsg}`,
|
|
684
|
+
amount: reqAmount,
|
|
685
|
+
display_amount: displayAmount,
|
|
686
|
+
network: ctx.resolvedNetwork,
|
|
687
|
+
}, { txId: ctx.txId });
|
|
688
|
+
ctx.eventBus?.emit('transaction:failed', {
|
|
689
|
+
walletId: ctx.walletId,
|
|
690
|
+
txId: ctx.txId,
|
|
691
|
+
error: `Receipt timeout: ${errMsg}`,
|
|
692
|
+
network: ctx.resolvedNetwork,
|
|
693
|
+
type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
|
|
694
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
695
|
+
});
|
|
696
|
+
throw new WAIaaSError('TRANSACTION_TIMEOUT', {
|
|
697
|
+
message: `UserOperation receipt timed out: ${errMsg}`,
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
// Generic fallback
|
|
701
|
+
await ctx.db
|
|
702
|
+
.update(transactions)
|
|
703
|
+
.set({ status: 'FAILED', error: errMsg })
|
|
704
|
+
.where(eq(transactions.id, ctx.txId));
|
|
705
|
+
ctx.metricsCounter?.increment('tx.failed', { network: ctx.resolvedNetwork });
|
|
706
|
+
void ctx.notificationService?.notify('TX_FAILED', ctx.walletId, {
|
|
707
|
+
txId: ctx.txId,
|
|
708
|
+
error: errMsg,
|
|
709
|
+
amount: reqAmount,
|
|
710
|
+
display_amount: displayAmount,
|
|
711
|
+
network: ctx.resolvedNetwork,
|
|
712
|
+
}, { txId: ctx.txId });
|
|
713
|
+
ctx.eventBus?.emit('transaction:failed', {
|
|
714
|
+
walletId: ctx.walletId,
|
|
715
|
+
txId: ctx.txId,
|
|
716
|
+
error: errMsg,
|
|
717
|
+
network: ctx.resolvedNetwork,
|
|
718
|
+
type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
|
|
719
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
720
|
+
});
|
|
721
|
+
throw new WAIaaSError('CHAIN_ERROR', { message: errMsg });
|
|
722
|
+
}
|
|
723
|
+
finally {
|
|
724
|
+
if (privateKey) {
|
|
725
|
+
ctx.keyStore.releaseKey(privateKey);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
// ---------------------------------------------------------------------------
|
|
730
|
+
// Stage 5: On-chain execution (CONC-01 retry loop)
|
|
731
|
+
// ---------------------------------------------------------------------------
|
|
732
|
+
/**
|
|
733
|
+
* Stage 5: Build -> Simulate -> Sign -> Submit with CONC-01 retry logic.
|
|
734
|
+
*
|
|
735
|
+
* For smart accounts (accountType === 'smart'), delegates to stage5ExecuteSmartAccount
|
|
736
|
+
* which uses the UserOperation pipeline (BundlerClient + PaymasterClient).
|
|
737
|
+
*
|
|
738
|
+
* For EOA accounts, uses the existing buildByType -> simulate -> sign -> submit path.
|
|
739
|
+
*
|
|
740
|
+
* ChainError category-based retry:
|
|
741
|
+
* - PERMANENT: immediate FAILED, no retry
|
|
742
|
+
* - TRANSIENT: exponential backoff (1s, 2s, 4s), max 3 retries (retryCount >= 3 guard)
|
|
743
|
+
* - STALE: rebuild from Stage 5a, max 1 (retryCount >= 1 guard)
|
|
744
|
+
*
|
|
745
|
+
* retryCount is shared between TRANSIENT and STALE to limit total retry count.
|
|
746
|
+
* Total attempts: initial 1 + up to 3 retries = 4 max.
|
|
747
|
+
*/
|
|
748
|
+
export async function stage5Execute(ctx) {
|
|
749
|
+
// Smart account UserOperation path
|
|
750
|
+
if (ctx.wallet.accountType === 'smart') {
|
|
751
|
+
await stage5ExecuteSmartAccount(ctx);
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
// v31.4: ApiDirectResult path -- skip on-chain execution entirely (HDESIGN-01)
|
|
755
|
+
if (ctx.actionResult) {
|
|
756
|
+
const result = ctx.actionResult;
|
|
757
|
+
// Update transaction status to CONFIRMED with API direct result metadata
|
|
758
|
+
await ctx.db
|
|
759
|
+
.update(transactions)
|
|
760
|
+
.set({
|
|
761
|
+
status: 'CONFIRMED',
|
|
762
|
+
metadata: JSON.stringify({
|
|
763
|
+
apiDirect: true,
|
|
764
|
+
provider: result.provider,
|
|
765
|
+
action: result.action,
|
|
766
|
+
externalId: result.externalId,
|
|
767
|
+
resultStatus: result.status,
|
|
768
|
+
data: result.data,
|
|
769
|
+
...(result.metadata ?? {}),
|
|
770
|
+
}),
|
|
771
|
+
})
|
|
772
|
+
.where(eq(transactions.id, ctx.txId));
|
|
773
|
+
// Audit log: TX_CONFIRMED (API direct)
|
|
774
|
+
if (ctx.sqlite) {
|
|
775
|
+
insertAuditLog(ctx.sqlite, {
|
|
776
|
+
eventType: 'TX_CONFIRMED',
|
|
777
|
+
actor: ctx.sessionId ?? 'system',
|
|
778
|
+
walletId: ctx.walletId,
|
|
779
|
+
txId: ctx.txId,
|
|
780
|
+
details: {
|
|
781
|
+
provider: result.provider,
|
|
782
|
+
action: result.action,
|
|
783
|
+
externalId: result.externalId,
|
|
784
|
+
apiDirect: true,
|
|
785
|
+
chain: ctx.wallet.chain,
|
|
786
|
+
network: ctx.resolvedNetwork,
|
|
787
|
+
},
|
|
788
|
+
severity: 'info',
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
// Fire-and-forget: notify TX_CONFIRMED
|
|
792
|
+
const apiDirectAmount = formatNotificationAmount(ctx.request, ctx.wallet.chain);
|
|
793
|
+
const apiDirectDisplayAmount = await resolveDisplayAmount(ctx.amountUsd ?? null, ctx.settingsService, ctx.forexRateService);
|
|
794
|
+
void ctx.notificationService?.notify('TX_CONFIRMED', ctx.walletId, {
|
|
795
|
+
txId: ctx.txId,
|
|
796
|
+
provider: result.provider,
|
|
797
|
+
action: result.action,
|
|
798
|
+
externalId: result.externalId,
|
|
799
|
+
network: ctx.resolvedNetwork,
|
|
800
|
+
amount: apiDirectAmount,
|
|
801
|
+
to: resolveNotificationTo(ctx.request, ctx.resolvedNetwork, ctx.contractNameRegistry),
|
|
802
|
+
display_amount: apiDirectDisplayAmount,
|
|
803
|
+
}, { txId: ctx.txId });
|
|
804
|
+
// Emit transaction:completed event (txHash = externalId for API direct)
|
|
805
|
+
ctx.eventBus?.emit('transaction:completed', {
|
|
806
|
+
walletId: ctx.walletId,
|
|
807
|
+
txId: ctx.txId,
|
|
808
|
+
txHash: result.externalId,
|
|
809
|
+
network: ctx.resolvedNetwork,
|
|
810
|
+
type: 'CONTRACT_CALL',
|
|
811
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
812
|
+
});
|
|
813
|
+
// Increment metrics
|
|
814
|
+
ctx.metricsCounter?.increment('tx.completed', { network: ctx.resolvedNetwork });
|
|
815
|
+
return; // Skip on-chain execution
|
|
816
|
+
}
|
|
817
|
+
// --- EOA execution path (unchanged) ---
|
|
818
|
+
const reqAmount = formatNotificationAmount(ctx.request, ctx.wallet.chain);
|
|
819
|
+
// [Phase 139] Resolve display amount once for all Stage 5 notifications
|
|
820
|
+
const displayAmount = await resolveDisplayAmount(ctx.amountUsd ?? null, ctx.settingsService, ctx.forexRateService);
|
|
821
|
+
let retryCount = 0;
|
|
822
|
+
// Outer buildLoop: STALE errors return here to rebuild from Stage 5a
|
|
823
|
+
buildLoop: while (true) {
|
|
824
|
+
try {
|
|
825
|
+
// Stage 5a: Build unsigned transaction (type-routed)
|
|
826
|
+
ctx.unsignedTx = await buildByType(ctx.adapter, ctx.request, ctx.wallet.publicKey);
|
|
827
|
+
// Stage 5b: Simulate (with RPC metrics)
|
|
828
|
+
const simStart = Date.now();
|
|
829
|
+
ctx.metricsCounter?.increment('rpc.calls', { network: ctx.resolvedNetwork });
|
|
830
|
+
const simResult = await ctx.adapter.simulateTransaction(ctx.unsignedTx);
|
|
831
|
+
ctx.metricsCounter?.recordLatency('rpc.latency', Date.now() - simStart, { network: ctx.resolvedNetwork });
|
|
832
|
+
if (!simResult.success) {
|
|
833
|
+
ctx.metricsCounter?.increment('rpc.errors', { network: ctx.resolvedNetwork });
|
|
834
|
+
ctx.metricsCounter?.increment('tx.failed', { network: ctx.resolvedNetwork });
|
|
835
|
+
await ctx.db
|
|
836
|
+
.update(transactions)
|
|
837
|
+
.set({ status: 'FAILED', error: simResult.error ?? 'Simulation failed' })
|
|
838
|
+
.where(eq(transactions.id, ctx.txId));
|
|
839
|
+
// Audit log: TX_FAILED (simulation failure)
|
|
840
|
+
if (ctx.sqlite) {
|
|
841
|
+
insertAuditLog(ctx.sqlite, {
|
|
842
|
+
eventType: 'TX_FAILED',
|
|
843
|
+
actor: ctx.sessionId ?? 'system',
|
|
844
|
+
walletId: ctx.walletId,
|
|
845
|
+
txId: ctx.txId,
|
|
846
|
+
details: { error: simResult.error ?? 'Simulation failed', stage: 5, chain: ctx.wallet.chain, network: ctx.resolvedNetwork },
|
|
847
|
+
severity: 'warning',
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
// Fire-and-forget: notify TX_FAILED on simulation failure
|
|
851
|
+
void ctx.notificationService?.notify('TX_FAILED', ctx.walletId, {
|
|
852
|
+
txId: ctx.txId,
|
|
853
|
+
error: simResult.error ?? 'Simulation failed',
|
|
854
|
+
amount: reqAmount,
|
|
855
|
+
display_amount: displayAmount,
|
|
856
|
+
network: ctx.resolvedNetwork,
|
|
857
|
+
}, { txId: ctx.txId });
|
|
858
|
+
// v1.6: emit transaction:failed event (simulation failure)
|
|
859
|
+
ctx.eventBus?.emit('transaction:failed', {
|
|
860
|
+
walletId: ctx.walletId,
|
|
861
|
+
txId: ctx.txId,
|
|
862
|
+
error: simResult.error ?? 'Simulation failed',
|
|
863
|
+
network: ctx.resolvedNetwork,
|
|
864
|
+
type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
|
|
865
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
866
|
+
});
|
|
867
|
+
throw new WAIaaSError('SIMULATION_FAILED', {
|
|
868
|
+
message: simResult.error ?? 'Transaction simulation failed',
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
// Stage 5c: Decrypt private key, sign
|
|
872
|
+
// CRITICAL: key MUST be released in finally block
|
|
873
|
+
let privateKey = null;
|
|
874
|
+
try {
|
|
875
|
+
privateKey = await ctx.keyStore.decryptPrivateKey(ctx.walletId, ctx.masterPassword);
|
|
876
|
+
ctx.signedTx = await ctx.adapter.signTransaction(ctx.unsignedTx, privateKey);
|
|
877
|
+
}
|
|
878
|
+
finally {
|
|
879
|
+
if (privateKey) {
|
|
880
|
+
ctx.keyStore.releaseKey(privateKey);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
// Stage 5d: Submit (with RPC metrics)
|
|
884
|
+
const submitStart = Date.now();
|
|
885
|
+
ctx.metricsCounter?.increment('rpc.calls', { network: ctx.resolvedNetwork });
|
|
886
|
+
ctx.submitResult = await ctx.adapter.submitTransaction(ctx.signedTx);
|
|
887
|
+
ctx.metricsCounter?.recordLatency('rpc.latency', Date.now() - submitStart, { network: ctx.resolvedNetwork });
|
|
888
|
+
// Success: increment tx.submitted counter
|
|
889
|
+
ctx.metricsCounter?.increment('tx.submitted', { network: ctx.resolvedNetwork });
|
|
890
|
+
// Success: Update DB SUBMITTED + txHash
|
|
891
|
+
await ctx.db
|
|
892
|
+
.update(transactions)
|
|
893
|
+
.set({ status: 'SUBMITTED', txHash: ctx.submitResult.txHash })
|
|
894
|
+
.where(eq(transactions.id, ctx.txId));
|
|
895
|
+
// Audit log: TX_SUBMITTED
|
|
896
|
+
if (ctx.sqlite) {
|
|
897
|
+
const txType = ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER';
|
|
898
|
+
const auditDetails = {
|
|
899
|
+
txHash: ctx.submitResult.txHash,
|
|
900
|
+
chain: ctx.wallet.chain,
|
|
901
|
+
network: ctx.resolvedNetwork,
|
|
902
|
+
type: txType,
|
|
903
|
+
};
|
|
904
|
+
// v31.14 DEPL-06: log keccak256(bytecode) for CONTRACT_DEPLOY audit trail
|
|
905
|
+
if (txType === 'CONTRACT_DEPLOY' && 'bytecode' in ctx.request) {
|
|
906
|
+
const { keccak256, toBytes } = await import('viem');
|
|
907
|
+
auditDetails.bytecodeHash = keccak256(toBytes(ctx.request.bytecode));
|
|
908
|
+
}
|
|
909
|
+
insertAuditLog(ctx.sqlite, {
|
|
910
|
+
eventType: 'TX_SUBMITTED',
|
|
911
|
+
actor: ctx.sessionId ?? 'system',
|
|
912
|
+
walletId: ctx.walletId,
|
|
913
|
+
txId: ctx.txId,
|
|
914
|
+
details: auditDetails,
|
|
915
|
+
severity: 'info',
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
// Fire-and-forget: notify TX_SUBMITTED
|
|
919
|
+
void ctx.notificationService?.notify('TX_SUBMITTED', ctx.walletId, {
|
|
920
|
+
txId: ctx.txId,
|
|
921
|
+
txHash: ctx.submitResult.txHash,
|
|
922
|
+
amount: reqAmount,
|
|
923
|
+
to: resolveNotificationTo(ctx.request, ctx.resolvedNetwork, ctx.contractNameRegistry),
|
|
924
|
+
display_amount: displayAmount,
|
|
925
|
+
network: ctx.resolvedNetwork,
|
|
926
|
+
}, { txId: ctx.txId });
|
|
927
|
+
// v1.6: emit wallet:activity TX_SUBMITTED event
|
|
928
|
+
ctx.eventBus?.emit('wallet:activity', {
|
|
929
|
+
walletId: ctx.walletId,
|
|
930
|
+
activity: 'TX_SUBMITTED',
|
|
931
|
+
details: { txId: ctx.txId, txHash: ctx.submitResult.txHash },
|
|
932
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
933
|
+
});
|
|
934
|
+
return; // Success -- exit the loop
|
|
935
|
+
}
|
|
936
|
+
catch (err) {
|
|
937
|
+
// Non-ChainError: rethrow as-is (WAIaaSError, validation errors, etc.)
|
|
938
|
+
if (!(err instanceof ChainError)) {
|
|
939
|
+
throw err;
|
|
940
|
+
}
|
|
941
|
+
// ChainError: category-based retry logic
|
|
942
|
+
switch (err.category) {
|
|
943
|
+
case 'PERMANENT': {
|
|
944
|
+
// Immediate failure, no retry
|
|
945
|
+
ctx.metricsCounter?.increment('rpc.errors', { network: ctx.resolvedNetwork });
|
|
946
|
+
ctx.metricsCounter?.increment('tx.failed', { network: ctx.resolvedNetwork });
|
|
947
|
+
await ctx.db
|
|
948
|
+
.update(transactions)
|
|
949
|
+
.set({ status: 'FAILED', error: err.message })
|
|
950
|
+
.where(eq(transactions.id, ctx.txId));
|
|
951
|
+
// Audit log: TX_FAILED (permanent chain error)
|
|
952
|
+
if (ctx.sqlite) {
|
|
953
|
+
insertAuditLog(ctx.sqlite, {
|
|
954
|
+
eventType: 'TX_FAILED',
|
|
955
|
+
actor: ctx.sessionId ?? 'system',
|
|
956
|
+
walletId: ctx.walletId,
|
|
957
|
+
txId: ctx.txId,
|
|
958
|
+
details: { error: err.message, stage: 5, chain: ctx.wallet.chain, network: ctx.resolvedNetwork },
|
|
959
|
+
severity: 'warning',
|
|
960
|
+
});
|
|
961
|
+
}
|
|
962
|
+
// Fire-and-forget: notify TX_FAILED
|
|
963
|
+
void ctx.notificationService?.notify('TX_FAILED', ctx.walletId, {
|
|
964
|
+
txId: ctx.txId,
|
|
965
|
+
error: err.message,
|
|
966
|
+
amount: reqAmount,
|
|
967
|
+
display_amount: displayAmount,
|
|
968
|
+
network: ctx.resolvedNetwork,
|
|
969
|
+
}, { txId: ctx.txId });
|
|
970
|
+
// v1.6: emit transaction:failed event (permanent chain error)
|
|
971
|
+
ctx.eventBus?.emit('transaction:failed', {
|
|
972
|
+
walletId: ctx.walletId,
|
|
973
|
+
txId: ctx.txId,
|
|
974
|
+
error: err.message,
|
|
975
|
+
network: ctx.resolvedNetwork,
|
|
976
|
+
type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
|
|
977
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
978
|
+
});
|
|
979
|
+
throw new WAIaaSError('CHAIN_ERROR', {
|
|
980
|
+
message: err.message,
|
|
981
|
+
cause: err,
|
|
982
|
+
});
|
|
983
|
+
}
|
|
984
|
+
case 'TRANSIENT': {
|
|
985
|
+
ctx.metricsCounter?.increment('rpc.errors', { network: ctx.resolvedNetwork });
|
|
986
|
+
if (retryCount >= 3) {
|
|
987
|
+
// Max retries exhausted
|
|
988
|
+
ctx.metricsCounter?.increment('tx.failed', { network: ctx.resolvedNetwork });
|
|
989
|
+
await ctx.db
|
|
990
|
+
.update(transactions)
|
|
991
|
+
.set({ status: 'FAILED', error: `${err.code} (max retries exceeded)` })
|
|
992
|
+
.where(eq(transactions.id, ctx.txId));
|
|
993
|
+
// Fire-and-forget: notify TX_FAILED
|
|
994
|
+
void ctx.notificationService?.notify('TX_FAILED', ctx.walletId, {
|
|
995
|
+
txId: ctx.txId,
|
|
996
|
+
error: `${err.code} (max retries exceeded)`,
|
|
997
|
+
amount: reqAmount,
|
|
998
|
+
display_amount: displayAmount,
|
|
999
|
+
network: ctx.resolvedNetwork,
|
|
1000
|
+
}, { txId: ctx.txId });
|
|
1001
|
+
// v1.6: emit transaction:failed event (transient max retries)
|
|
1002
|
+
ctx.eventBus?.emit('transaction:failed', {
|
|
1003
|
+
walletId: ctx.walletId,
|
|
1004
|
+
txId: ctx.txId,
|
|
1005
|
+
error: `${err.code} (max retries exceeded)`,
|
|
1006
|
+
network: ctx.resolvedNetwork,
|
|
1007
|
+
type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
|
|
1008
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
1009
|
+
});
|
|
1010
|
+
throw new WAIaaSError('CHAIN_ERROR', {
|
|
1011
|
+
message: `${err.message} (max retries exceeded)`,
|
|
1012
|
+
cause: err,
|
|
1013
|
+
});
|
|
1014
|
+
}
|
|
1015
|
+
// Exponential backoff: 1s, 2s, 4s
|
|
1016
|
+
await sleep(1000 * Math.pow(2, retryCount));
|
|
1017
|
+
retryCount++;
|
|
1018
|
+
continue buildLoop; // Retry from Stage 5a (rebuild)
|
|
1019
|
+
}
|
|
1020
|
+
case 'STALE': {
|
|
1021
|
+
ctx.metricsCounter?.increment('rpc.errors', { network: ctx.resolvedNetwork });
|
|
1022
|
+
if (retryCount >= 1) {
|
|
1023
|
+
// Stale retry exhausted (shared retryCount)
|
|
1024
|
+
ctx.metricsCounter?.increment('tx.failed', { network: ctx.resolvedNetwork });
|
|
1025
|
+
await ctx.db
|
|
1026
|
+
.update(transactions)
|
|
1027
|
+
.set({ status: 'FAILED', error: `${err.code} (stale retry exhausted)` })
|
|
1028
|
+
.where(eq(transactions.id, ctx.txId));
|
|
1029
|
+
// Fire-and-forget: notify TX_FAILED
|
|
1030
|
+
void ctx.notificationService?.notify('TX_FAILED', ctx.walletId, {
|
|
1031
|
+
txId: ctx.txId,
|
|
1032
|
+
error: `${err.code} (stale retry exhausted)`,
|
|
1033
|
+
amount: reqAmount,
|
|
1034
|
+
display_amount: displayAmount,
|
|
1035
|
+
network: ctx.resolvedNetwork,
|
|
1036
|
+
}, { txId: ctx.txId });
|
|
1037
|
+
// v1.6: emit transaction:failed event (stale retry exhausted)
|
|
1038
|
+
ctx.eventBus?.emit('transaction:failed', {
|
|
1039
|
+
walletId: ctx.walletId,
|
|
1040
|
+
txId: ctx.txId,
|
|
1041
|
+
error: `${err.code} (stale retry exhausted)`,
|
|
1042
|
+
network: ctx.resolvedNetwork,
|
|
1043
|
+
type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
|
|
1044
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
1045
|
+
});
|
|
1046
|
+
throw new WAIaaSError('CHAIN_ERROR', {
|
|
1047
|
+
message: `${err.message} (stale retry exhausted)`,
|
|
1048
|
+
cause: err,
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1051
|
+
// Rebuild from Stage 5a with new blockhash/nonce
|
|
1052
|
+
retryCount++;
|
|
1053
|
+
continue buildLoop;
|
|
1054
|
+
}
|
|
1055
|
+
default: {
|
|
1056
|
+
// Unknown category: treat as permanent
|
|
1057
|
+
await ctx.db
|
|
1058
|
+
.update(transactions)
|
|
1059
|
+
.set({ status: 'FAILED', error: err.message })
|
|
1060
|
+
.where(eq(transactions.id, ctx.txId));
|
|
1061
|
+
throw new WAIaaSError('CHAIN_ERROR', {
|
|
1062
|
+
message: err.message,
|
|
1063
|
+
cause: err,
|
|
1064
|
+
});
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
//# sourceMappingURL=stage5-execute.js.map
|