diff --git a/packages/core/src/contracts/invoke-contract.ts b/packages/core/src/contracts/invoke-contract.ts index 1c1d46fc..6f046845 100644 --- a/packages/core/src/contracts/invoke-contract.ts +++ b/packages/core/src/contracts/invoke-contract.ts @@ -5,12 +5,11 @@ import { resolveNetwork } from "../networks/resolve-network.js"; import { checkBinary } from "../shell/check-binary.js"; import { runCommand } from "../shell/run-command.js"; import { buildStellarNetworkArgs } from "../stellar-cli/build-stellar-network-args.js"; +import { STELLAR_CLI_SIGNING_FAILURE_REGEX } from "../stellar-cli/version.js"; import { assertSafeSourceAccount } from "./source-account.js"; import { buildReadCallHint, isReadCallFailure, parseInvokeTarget } from "./invoke-target.js"; import { resolveCliMethodArgs } from "./resolve-method-args.js"; -const INVOKE_SIGNING_FAILURE_REGEX = /xdr processing error: xdr value invalid/i; - export type { InvokeTarget } from "./invoke-target.js"; export { parseInvokeTarget } from "./invoke-target.js"; @@ -85,7 +84,7 @@ export async function invokeContract(options: InvokeContractOptions) { if ( error instanceof CaatingaError && error.code === CaatingaErrorCode.INVOKE_FAILED && - INVOKE_SIGNING_FAILURE_REGEX.test(`${error.message}\n${error.hint ?? ""}`) + STELLAR_CLI_SIGNING_FAILURE_REGEX.test(`${error.message}\n${error.hint ?? ""}`) ) { throw new CaatingaError( error.message, diff --git a/packages/core/src/stellar-cli/recover-deploy-contract-id.test.ts b/packages/core/src/stellar-cli/recover-deploy-contract-id.test.ts index 4b73d22c..703937e0 100644 --- a/packages/core/src/stellar-cli/recover-deploy-contract-id.test.ts +++ b/packages/core/src/stellar-cli/recover-deploy-contract-id.test.ts @@ -6,6 +6,7 @@ import { isLikelyPublicKeySource, tryRecoverContractIdFromDeployFailure, } from "./recover-deploy-contract-id.js"; +import { STELLAR_CLI_SIGNING_FAILURE_REGEX } from "./version.js"; const runCommandMock = vi.hoisted(() => vi.fn()); @@ -175,3 +176,15 @@ describe("horizon recovery timeout", () => { ).resolves.toBeNull(); }); }); + +describe("STELLAR_CLI_SIGNING_FAILURE_REGEX", () => { + it("should_match_the_signing_failure_both_the_invoke_and_recovery_paths_key_off", () => { + expect( + STELLAR_CLI_SIGNING_FAILURE_REGEX.test("error: xdr processing error: xdr value invalid") + ).toBe(true); + }); + + it("should_not_match_unrelated_stellar_cli_failures", () => { + expect(STELLAR_CLI_SIGNING_FAILURE_REGEX.test("error: simulation failed")).toBe(false); + }); +}); diff --git a/packages/core/src/stellar-cli/recover-deploy-contract-id.ts b/packages/core/src/stellar-cli/recover-deploy-contract-id.ts index 61a98d3e..52d11064 100644 --- a/packages/core/src/stellar-cli/recover-deploy-contract-id.ts +++ b/packages/core/src/stellar-cli/recover-deploy-contract-id.ts @@ -4,12 +4,12 @@ import { NETWORK_METADATA_BY_PASSPHRASE } from "../networks/network-metadata.js" import { runCommand } from "../shell/run-command.js"; import { buildStellarNetworkArgsFromConfig } from "./build-stellar-network-args.js"; import { parseContractId } from "./parse-contract-id.js"; +import { STELLAR_CLI_SIGNING_FAILURE_REGEX } from "./version.js"; const TX_HASH_REGEX = /Transaction hash is ([a-f0-9]{64})/i; /** Horizon is only consulted on the deploy-recovery path; fail fast rather than stall a failed deploy. */ export const HORIZON_RECOVERY_TIMEOUT_MS = 10_000; -const DEPLOY_SIGNING_FAILURE_REGEX = /xdr processing error: xdr value invalid/i; type HorizonOperation = { transaction_successful?: boolean; @@ -117,7 +117,7 @@ export async function tryRecoverContractIdFromDeployFailure(options: { /** Abort the Horizon lookup after this many ms (default {@link HORIZON_RECOVERY_TIMEOUT_MS}). */ horizonTimeoutMs?: number; }): Promise { - if (!DEPLOY_SIGNING_FAILURE_REGEX.test(options.output)) { + if (!STELLAR_CLI_SIGNING_FAILURE_REGEX.test(options.output)) { return null; } diff --git a/packages/core/src/stellar-cli/version.ts b/packages/core/src/stellar-cli/version.ts index d106d5db..259f614b 100644 --- a/packages/core/src/stellar-cli/version.ts +++ b/packages/core/src/stellar-cli/version.ts @@ -4,6 +4,13 @@ import { CaatingaError, CaatingaErrorCode } from "../errors/CaatingaError.js"; // 22.x fails to sign `stellar contract invoke` (xdr value invalid); 23.0.0+ is required. export const STELLAR_CLI_MIN_VERSION = "23.0.0"; +/** + * Output signature of the signing failure that {@link STELLAR_CLI_MIN_VERSION} guards + * against. The invoke hint and the deploy-recovery path both key off this one pattern so + * they cannot disagree about which failures are the 22.x signing bug. + */ +export const STELLAR_CLI_SIGNING_FAILURE_REGEX = /xdr processing error: xdr value invalid/i; + const STELLAR_CLI_SEMVER_REGEX = /\b(\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?(?:\+[0-9A-Za-z-.]+)?)\b/; export function parseStellarCliVersion(output: string): string {