* Start the x402 proxy in the background. * Called from register() because OpenClaw's loader only invokes register(), * treating activate() as an alias (def.register ?? def.activate).
( api: OpenClawPluginApi, startupGeneration?: number, )
| 739 | * treating activate() as an alias (def.register ?? def.activate). |
| 740 | */ |
| 741 | async function startProxyInBackground( |
| 742 | api: OpenClawPluginApi, |
| 743 | startupGeneration?: number, |
| 744 | ): Promise<boolean> { |
| 745 | const proc = process as ProcessWithClawRouterState; |
| 746 | if (startupGeneration !== undefined && isProxyStartupCurrent(startupGeneration, proc)) { |
| 747 | proc.__clawrouterStartupPhase = "starting"; |
| 748 | } |
| 749 | |
| 750 | // Resolve wallet key: plugin config → saved file → env var → auto-generate. |
| 751 | // pluginConfig.walletKey is declared in openclaw.plugin.json configSchema but |
| 752 | // was previously never read here — that was a bug. |
| 753 | const configKey = api.pluginConfig?.walletKey as string | undefined; |
| 754 | let wallet: WalletResolution; |
| 755 | |
| 756 | if (typeof configKey === "string" && /^0x[0-9a-fA-F]{64}$/.test(configKey)) { |
| 757 | const account = privateKeyToAccount(configKey as `0x${string}`); |
| 758 | wallet = { key: configKey, address: account.address, source: "config" }; |
| 759 | } else { |
| 760 | if (configKey !== undefined) { |
| 761 | api.logger.warn( |
| 762 | `pluginConfig.walletKey is set but invalid (expected 0x + 64 hex chars) — falling back to saved wallet`, |
| 763 | ); |
| 764 | } |
| 765 | wallet = await resolveOrGenerateWalletKey(); |
| 766 | } |
| 767 | |
| 768 | // Log wallet source |
| 769 | if (wallet.source === "generated") { |
| 770 | api.logger.warn(`════════════════════════════════════════════════`); |
| 771 | api.logger.warn(` NEW WALLET GENERATED — BACK UP YOUR KEY NOW!`); |
| 772 | api.logger.warn(` Address : ${wallet.address}`); |
| 773 | api.logger.warn(` Run /wallet export to get your private key`); |
| 774 | api.logger.warn(` Losing this key = losing your USDC funds`); |
| 775 | api.logger.warn(`════════════════════════════════════════════════`); |
| 776 | } else if (wallet.source === "saved") { |
| 777 | api.logger.info(`Using saved wallet: ${wallet.address}`); |
| 778 | } else if (wallet.source === "config") { |
| 779 | api.logger.info(`Using wallet from plugin config: ${wallet.address}`); |
| 780 | } else { |
| 781 | api.logger.info(`Using wallet from BLOCKRUN_WALLET_KEY: ${wallet.address}`); |
| 782 | } |
| 783 | |
| 784 | // Resolve routing config overrides from plugin config |
| 785 | const routingConfig = api.pluginConfig?.routing as Partial<RoutingConfig> | undefined; |
| 786 | |
| 787 | const maxCostPerRunUsd = |
| 788 | typeof api.pluginConfig?.maxCostPerRun === "number" |
| 789 | ? (api.pluginConfig.maxCostPerRun as number) |
| 790 | : undefined; |
| 791 | |
| 792 | const maxCostPerRunMode: "graceful" | "strict" = |
| 793 | api.pluginConfig?.maxCostPerRunMode === "strict" ? "strict" : "graceful"; |
| 794 | |
| 795 | if (maxCostPerRunUsd !== undefined) { |
| 796 | api.logger.info( |
| 797 | `Cost cap: $${maxCostPerRunUsd.toFixed(2)} per session (mode: ${maxCostPerRunMode})`, |
| 798 | ); |
no test coverage detected