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