diff --git a/.changelog/add-machine-usd-funding.md b/.changelog/add-machine-usd-funding.md deleted file mode 100644 index f82e69a..0000000 --- a/.changelog/add-machine-usd-funding.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -wallet-cli: minor ---- - -Add a machineUSD funding flow that opens the wallet onramp and waits for the mainnet token balance to increase. diff --git a/src/cli.ts b/src/cli.ts index 4964da5..4cffbc2 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -182,7 +182,6 @@ cli.command("fund", { action: fundAction({ credits: options.credits, crypto: options.crypto, - machineUsd: options["machine-usd"], referralCode: options["referral-code"] ?? options.claim, }), address: options.address, @@ -655,7 +654,6 @@ function describeCli() { "Open the direct crypto funding flow (bridge on mainnet, faucet on testnet)", ), flag("credits", "--credits", "Open the credits purchase flow"), - flag("machine_usd", "--machine-usd", "Open the machineUSD purchase flow"), option("referral_code", "--referral-code", "Referral code to claim while funding", { valueName: "CODE", }), diff --git a/src/commands/fund.ts b/src/commands/fund.ts index d8e41e3..b429efe 100644 --- a/src/commands/fund.ts +++ b/src/commands/fund.ts @@ -1,5 +1,4 @@ import type { Provider as CoreProvider } from "accounts"; -import { isAddress } from "viem"; import { Actions } from "viem/tempo"; import { usageError } from "../shared/errors.js"; @@ -10,14 +9,7 @@ import { createProvider } from "../provider.js"; import { loadWalletState } from "../wallet/store.js"; import { queryCreditBalance } from "./credits.js"; -const defaultMachineUsdOrigin = "https://machine-usd.porto.workers.dev"; - -export type FundAction = "fund" | "crypto" | "credits" | "machine-usd" | "claim"; - -export type MachineUsdConfig = { - chainId: number; - tokenAddress: `0x${string}`; -}; +export type FundAction = "fund" | "crypto" | "credits" | "claim"; export async function runFundingFlow(options: { action: FundAction; @@ -34,29 +26,18 @@ export async function runFundingFlow(options: { if (!walletAddress && options.action !== "claim") throw usageError("Configuration missing: No wallet configured. Run 'tempo wallet login'."); - const selectedChainId = chainId(options.network); - const machineUsdConfig = - options.action === "machine-usd" ? await queryMachineUsdConfig() : undefined; - if (machineUsdConfig && selectedChainId !== machineUsdConfig.chainId) - throw usageError("machineUSD funding is only available on Tempo mainnet."); - const initial = await fundingBalance({ action: options.action, - chainId: selectedChainId, - token: machineUsdConfig?.tokenAddress, + chainId: chainId(options.network), walletAddress, }); - const url = fundUrl(options.action, { address: walletAddress ?? undefined, code: options.code }); + const url = fundUrl(options.action, { code: options.code }); console.error(`Fund URL: ${url}`); console.error(`Open this link on your device: ${url}`); if (!options.noBrowser) openExternal(url); - if (options.action === "machine-usd") { - console.error("Complete the machineUSD purchase in the wallet app."); - console.error("After purchasing machineUSD, return here to continue."); - console.error("Waiting for machineUSD..."); - } else if (options.action === "credits") { + if (options.action === "credits") { console.error("Complete the credits purchase in the wallet app."); console.error("After purchasing credits, return here to continue."); console.error("Waiting for credits..."); @@ -67,9 +48,8 @@ export async function runFundingFlow(options: { const completed = await waitForFunding({ action: options.action, - chainId: selectedChainId, + chainId: chainId(options.network), initialRawBalance: initial.rawBalance, - token: machineUsdConfig?.tokenAddress, walletAddress, }); console.error("Funding received!"); @@ -86,10 +66,8 @@ export async function runFundingFlow(options: { export function fundAction(options: { credits?: boolean | undefined; crypto?: boolean | undefined; - machineUsd?: boolean | undefined; referralCode?: string | undefined; }): FundAction { - if (options.machineUsd) return "machine-usd"; if (options.credits) return "credits"; if (options.crypto) return "crypto"; if (options.referralCode) return "claim"; @@ -99,7 +77,6 @@ export function fundAction(options: { async function fundingBalance(options: { action: FundAction; chainId: number; - token?: `0x${string}` | undefined; walletAddress: string | null; }) { if (options.action === "credits") { @@ -127,7 +104,7 @@ async function fundingBalance(options: { const rawBalance = ( await Actions.token.getBalance(provider.getClient() as never, { account: options.walletAddress as `0x${string}`, - token: options.token ?? tokenAddress(options.chainId), + token: tokenAddress(options.chainId), }) ).amount; @@ -141,7 +118,6 @@ async function waitForFunding(options: { action: FundAction; chainId: number; initialRawBalance: bigint; - token?: `0x${string}` | undefined; walletAddress: string | null; }) { const pollMs = Number(process.env.TEMPO_WALLET_FUND_POLL_MS ?? 2_000); @@ -159,10 +135,7 @@ async function waitForFunding(options: { } } -export function fundUrl( - action: FundAction, - options: { address?: string | undefined; code?: string | undefined } = {}, -) { +export function fundUrl(action: FundAction, options: { code?: string | undefined } = {}) { // The CLI is an agent/MPP surface, so all funding handoffs land on the dedicated // /agent page rather than the consumer wallet home. const url = new URL("https://wallet.tempo.xyz/agent"); @@ -170,38 +143,7 @@ export function fundUrl( url.searchParams.set("claim", options.code); return url.toString(); } - url.searchParams.set( - "action", - action === "credits" || action === "machine-usd" ? "fund" : action, - ); + url.searchParams.set("action", action === "credits" ? "fund" : action); if (action === "credits") url.searchParams.set("intent", "credits"); - if (action === "machine-usd") { - url.searchParams.set("intent", "machine-usd"); - if (options.address) url.searchParams.set("address", options.address); - } return url.toString(); } - -/** Reads the deployed token address and chain used to detect a completed machineUSD purchase. */ -export async function queryMachineUsdConfig(options: { origin?: string | undefined } = {}) { - const origin = options.origin || process.env.TEMPO_MACHINE_USD_ORIGIN || defaultMachineUsdOrigin; - const response = await fetch(new URL("/v1/config", `${origin.replace(/\/$/, "")}/`).toString()); - const body = (await response.json().catch(() => null)) as { - chain_id?: unknown; - token_address?: unknown; - } | null; - if (!response.ok) throw new Error("Unable to load machineUSD configuration"); - if ( - !body || - typeof body.chain_id !== "number" || - !Number.isSafeInteger(body.chain_id) || - typeof body.token_address !== "string" || - !isAddress(body.token_address, { strict: false }) - ) - throw new Error("machineUSD configuration is invalid"); - - return { - chainId: body.chain_id, - tokenAddress: body.token_address as `0x${string}`, - } satisfies MachineUsdConfig; -} diff --git a/src/compat.ts b/src/compat.ts index ea5f849..60af830 100644 --- a/src/compat.ts +++ b/src/compat.ts @@ -56,12 +56,10 @@ async function runFundCompat(args: readonly string[]) { action: fundAction({ credits: args.includes("--credits"), crypto: args.includes("--crypto"), - machineUsd: args.includes("--machine-usd"), referralCode: stringArg(args, "--referral-code") ?? stringArg(args, "--claim"), }), address: stringArg(args, "--address"), code: stringArg(args, "--referral-code") ?? stringArg(args, "--claim"), - network: stringArg(args, "--network") ?? stringArg(args, "-n"), noBrowser: args.includes("--no-browser"), }); printCompatOutput(result, args); diff --git a/src/schemas.ts b/src/schemas.ts index e860b1a..bde2edc 100644 --- a/src/schemas.ts +++ b/src/schemas.ts @@ -324,7 +324,6 @@ export const fundOptions = z.object({ browser: z.boolean().default(true).describe("Open a browser; use --no-browser to disable"), crypto: z.boolean().optional().describe("Open the direct crypto funding flow"), credits: z.boolean().optional().describe("Open the credits purchase flow"), - "machine-usd": z.boolean().optional().describe("Open the machineUSD purchase flow"), "referral-code": z.string().optional().describe("Open referral-code redeem flow"), claim: z.string().optional().describe("Alias for --referral-code"), }); diff --git a/test/fund-compat.test.ts b/test/fund-compat.test.ts deleted file mode 100644 index 75838f1..0000000 --- a/test/fund-compat.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { afterEach, describe, expect, it, vi } from "vitest"; - -const mocks = vi.hoisted(() => ({ - runFundingFlow: vi.fn().mockResolvedValue({ status: "success" }), -})); - -vi.mock("../src/commands/fund.js", async (importOriginal) => ({ - ...(await importOriginal()), - runFundingFlow: mocks.runFundingFlow, -})); - -import { handleCompatCommand } from "../src/compat.js"; - -describe("fund compatibility", () => { - afterEach(() => { - vi.restoreAllMocks(); - mocks.runFundingFlow.mockClear(); - }); - - it.each(["--network", "-n"])("forwards %s to the funding flow", async (flag) => { - vi.spyOn(console, "log").mockImplementation(() => {}); - - await expect( - handleCompatCommand(["fund", "--machine-usd", flag, "testnet", "--no-browser"]), - ).resolves.toBe(true); - expect(mocks.runFundingFlow).toHaveBeenCalledWith( - expect.objectContaining({ action: "machine-usd", network: "testnet" }), - ); - }); -}); diff --git a/test/fund-services.test.ts b/test/fund-services.test.ts index 2fe7829..018fdfe 100644 --- a/test/fund-services.test.ts +++ b/test/fund-services.test.ts @@ -1,11 +1,6 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { - fundAction, - fundUrl, - queryMachineUsdConfig, - runFundingFlow, -} from "../src/commands/fund.js"; +import { fundAction, fundUrl, runFundingFlow } from "../src/commands/fund.js"; import { fetchServices, fetchServiceList } from "../src/commands/services.js"; import { expectUsageError, useTempHome } from "./helpers.js"; @@ -24,10 +19,6 @@ describe("fundAction", () => { expect(fundAction({ crypto: true })).toBe("crypto"); }); - it('returns "machine-usd" when machineUsd is set', () => { - expect(fundAction({ machineUsd: true })).toBe("machine-usd"); - }); - it('returns "claim" when a referral code is provided', () => { expect(fundAction({ referralCode: "ABC" })).toBe("claim"); }); @@ -36,12 +27,6 @@ describe("fundAction", () => { expect(fundAction({ credits: true, crypto: true, referralCode: "ABC" })).toBe("credits"); }); - it("prioritizes machineUSD over the other funding intents", () => { - expect(fundAction({ credits: true, crypto: true, machineUsd: true, referralCode: "ABC" })).toBe( - "machine-usd", - ); - }); - it("prioritizes crypto over referral code", () => { expect(fundAction({ crypto: true, referralCode: "ABC" })).toBe("crypto"); }); @@ -52,48 +37,12 @@ describe("fundUrl", () => { expect(fundUrl("fund")).toBe("https://wallet.tempo.xyz/agent?action=fund"); expect(fundUrl("crypto")).toBe("https://wallet.tempo.xyz/agent?action=crypto"); expect(fundUrl("credits")).toBe("https://wallet.tempo.xyz/agent?action=fund&intent=credits"); - expect(fundUrl("machine-usd", { address: "0x1111111111111111111111111111111111111111" })).toBe( - "https://wallet.tempo.xyz/agent?action=fund&intent=machine-usd&address=0x1111111111111111111111111111111111111111", - ); expect(fundUrl("claim", { code: "ABC123" })).toBe( "https://wallet.tempo.xyz/agent?claim=ABC123", ); }); }); -describe("queryMachineUsdConfig", () => { - afterEach(() => { - vi.restoreAllMocks(); - }); - - it("returns the public chain and token configuration", async () => { - const fetch = vi.spyOn(globalThis, "fetch").mockResolvedValue( - new Response( - JSON.stringify({ - chain_id: 4217, - token_address: "0x20C0000000000000000000000000000000000001", - }), - ), - ); - - await expect(queryMachineUsdConfig({ origin: "https://machine.example" })).resolves.toEqual({ - chainId: 4217, - tokenAddress: "0x20C0000000000000000000000000000000000001", - }); - expect(fetch).toHaveBeenCalledWith("https://machine.example/v1/config"); - }); - - it("rejects malformed public configuration", async () => { - vi.spyOn(globalThis, "fetch").mockResolvedValue( - new Response(JSON.stringify({ chain_id: 4217, token_address: "not-an-address" })), - ); - - await expect(queryMachineUsdConfig({ origin: "https://machine.example" })).rejects.toThrow( - "machineUSD configuration is invalid", - ); - }); -}); - describe("runFundingFlow", () => { let consoleError: ReturnType;