Skip to main content

FAQ

Short answers for common authoring, runtime, provider, and testnet questions.

Smart contract call failure​

If broadcast returns a mandatory-script-verify-flag-failed error, one or more inputs failed script verification.

Common causes:

Error shapeLikely cause
Script evaluated without error but finished with a false/empty top stack elementA predicate returned false — signature mismatch, wrong preimage, failed timelock, or output covenant mismatch.
Signature must be zero for failed CHECK(MULTI)SIG operationInvalid signature for checkSig / checkMultiSig, wrong sighash, or wrong key material in invoke.
OP_VERIFY failedAn explicit assert(...) boundary or fused verify helper rejected the path.

Start with How to Debug a Contract:

  1. Inspect bound.artifact and method ABI.
  2. Run methods.<name>.verify(...) locally.
  3. Only then move to MemoryProvider or testnet deploy/call.

Double-spend and missing-input errors​

You may see mempool or missing-input errors when retrying spends against stale UTXOs.

ErrorTypical meaning
txn-mempool-conflictYou tried to spend a UTXO that is already being spent by another unconfirmed transaction.
missing-inputs / Transaction invalid: missing-inputsThe UTXO was already confirmed in another spend.

For developers​

Providers can return UTXO sets that lag behind recent broadcasts, especially under heavy testnet traffic. Wait a few seconds and retry, or insert a short delay between consecutive calls:

const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

await deployed.methods.increase.call({}, { provider, signer, invoke });
await sleep(2_000);
await deployedAgain.methods.increase.call({}, { provider, signer, invoke });

Persist deployed outpoints (txid, vout, satoshis`) and refresh them after every successful spend. See Interact with a Deployed Contract.

For dApp users​

If two users spend the same contract instance concurrently, one transaction wins and the other fails against stale state. Refresh the latest UTXO and successor state before signing again.

TESTNET_WIF / private key errors​

Deploy and testnet scripts require a funded WIF in the environment.

SymptomFix
Set TESTNET_WIF in your .env file before deploying.Export a testnet key and add it to .env.
Input string too shortThe WIF variable is empty or malformed.
No sufficient utxosFund the WIF address on OP_CAT testnet before deploying.

Follow How to Deploy & Call for the guarded testnet flow. Never commit .env or hard-code WIFs in browser code.

Artifact or script mismatch after upgrade​

If verification succeeds locally but the on-chain script hash does not match:

  • Confirm you are using the same @opcat-labs/lambit version that produced the published artifact.
  • Re-run lambit compile and compare artifact.hex and ABI metadata.
  • For stateful contracts, confirm constructor args and current state match the UTXO you attached.

See How to Verify a Contract.

Stateful successor state surprises​

methods.<name>.next(state, args?) is pure. Use it to preview the successor state before you broadcast:

const next = counter.methods.increase.next({ count: 2n });
// { count: 3n }

If the spend fails after a successful next, check output covenants, sighash mode, and whether the method returns { outputs, check? } instead of { next, check? }. See Stateful Contracts and Sighash Types.

lambit compile / lambit artifact security​

Both commands execute the target module to collect contract exports. Only compile trusted code in CI or on your own machine.

CLI test discovery outside this repo​

lambit test wraps Mocha. Outside the Lambit package checkout, prefer an explicit config:

lambit test --config ./.mocharc.json

Use --no-config when you want Mocha config discovery disabled. See Installation.

Guarded testnet E2E​

lambit test --testnet and npm run test:testnet are opt-in. Set LAMBIT_RUN_TESTNET_E2E=1 and a funded TESTNET_WIF only when you intend to spend testnet coins.

Porting from sCrypt / scrypt-ts-opcat​

Translate class/decorator contracts into functional contract() definitions. Start with Basics for stateless ports and Stateful Contracts for @prop(true) state fields. The main shifts are immutable state returns ({ next, check? }), explicit prop schemas, and provider-driven deploy/call instead of mutable this writes.

Where to go next​