Methodology
DISCLAIMER // NFA // DYOR
This analysis is based on observations of the contract behavior. We are not smart contract security experts. This document aims to explain what the contract appears to do based on the code. It should not be considered a comprehensive security audit or financial advice. Always verify critical information independently and consult with blockchain security professionals for important decisions.
⊙ generated by robots | curated by humans
| METADATA | |
|---|---|
| Contract Address | 0x82eb1246...90cC37 (etherscan) |
| Network | Ethereum Mainnet |
| Analysis Date | 2026-06-02 |
Overview
This analysis worked from verified Solidity source. Because the contract is verified on Etherscan (Exact Match, Solidity 0.8.34), there was no decompilation step — the source is authoritative. The effort instead went into (a) reading the contract and its three verified dependencies, (b) decoding the constructor arguments to learn the exact wiring, (c) reconstructing on-chain state with cast to confirm the source matches reality, and (d) tracing a real withdrawal transaction to confirm the withdrawal path executes as written.
A key step was tracing the withdrawal: an early reading of the constructor calldata misattributed the burn-verifier address by one nibble, which suggested the verifier had no code. Tracing tx 0x45f7ccbc...4491d9 (tx) showed the true callee — 0x031b22ba...7Ab2ca (etherscan) — executing bn254 pairing precompiles and returning true. This confirmed addresses should be checked against execution rather than eyeballed calldata.
Thought Process
mindmap
root((TacitBridgeMixer))
Obtain
Etherscan getsourcecode
Verified Solidity 0.8.34
5 source files
Decode constructor args
Understand
Standalone, no proxy, no admin
Two directions: deposit / withdrawFromBurn
8 fixed ETH denominations
4 external dependencies
Dependencies
BitcoinLightRelay (verified)
SP1PoolRootVerifier (verified)
Succinct SP1 gateway
Groth16 verifier (unverified)
Verify On-Chain
cast call immutables
cast storage slots 0-25
poolIds, totalBalance
trace a real withdrawal
Risk
No roles on the mixer
Trust relocated to SNARKs + relay
Unverified Groth16 verifier
One day old, unaudited
Verification Guide
The analysis used Etherscan's API v2 for source, ABI, and creation metadata, and Foundry cast for on-chain reads and transaction tracing. The reference dApp (tacit.finance) and the upstream repository at the analyzed commit provided context for the Tacit-side semantics the bridge consumes.
External Resources
- Etherscan API v2 —
getsourcecode,getcontractcreation,txlist,getLogsfor source, deployment metadata, activity, and events. - TacitBridgeMixer.sol @ z0r0z/tacit (commit 9da5b4e) — upstream source at the analyzed commit.
- Succinct SP1 docs — the SP1 zkVM and
SP1VerifierGatewayused to verify Bitcoin pool-state proofs. - Tacit Project research — DNZN's prior coverage of the Bitcoin-side meta-protocol, including the shielded mixer primitive family.
Commandline Tools
Tip
Commands below use cast from the Foundry Toolkit. To run them, set the RPC URL environment variable:
Read the contract's immutable wiring
The contract has no admin, so its "configuration" is the set of immutable values fixed at deploy. Reading them confirms which relay and verifiers the bridge trusts.
# RELAY, BURN VERIFIER, TOKEN, ASSET, AND TREE PARAMETERS
cast call 0x82eb12463560e91a8b1d2312223e77c7c490cc37 "HEADER_RELAY()(address)"
cast call 0x82eb12463560e91a8b1d2312223e77c7c490cc37 "BURN_VERIFIER()(address)"
cast call 0x82eb12463560e91a8b1d2312223e77c7c490cc37 "TOKEN()(address)"
cast call 0x82eb12463560e91a8b1d2312223e77c7c490cc37 "UNIT_SCALE()(uint256)"
cast call 0x82eb12463560e91a8b1d2312223e77c7c490cc37 "totalBalance()(uint256)"
Enumerate the pools and verify denominations
# THE 8 POOL IDS AND THEIR DENOMINATIONS
cast call 0x82eb12463560e91a8b1d2312223e77c7c490cc37 "poolIds(uint256)(bytes32)" 0
cast call 0x82eb12463560e91a8b1d2312223e77c7c490cc37 "getPoolDenomination(bytes32)(uint256)" <pid>
Confirm storage layout
# SLOT 1 = totalBalance, SLOT 5 = poolIds LENGTH, SLOTS 6-25 = zeros[]
cast storage 0x82eb12463560e91a8b1d2312223e77c7c490cc37 1
cast storage 0x82eb12463560e91a8b1d2312223e77c7c490cc37 5
cast storage 0x82eb12463560e91a8b1d2312223e77c7c490cc37 7 # zeros[1] = Poseidon(0,0)
Verify the dependency wiring and SP1 state
# THE SP1 VERIFIER POINTS BACK AT THIS MIXER AND THE SAME ASSET
cast call 0x42ab3d9df0d5077ecfbd95adf3f99b3bea2a3ccb "MIXER()(address)"
cast call 0x42ab3d9df0d5077ecfbd95adf3f99b3bea2a3ccb "ASSET_ID()(bytes32)"
cast call 0x42ab3d9df0d5077ecfbd95adf3f99b3bea2a3ccb "SP1_VERIFIER()(address)"
cast call 0x42ab3d9df0d5077ecfbd95adf3f99b3bea2a3ccb "lastProvenPoolIndex(uint8)(uint64)" 0
# THE RELAY TIP HEIGHT (BITCOIN BLOCK THE BRIDGE IS ANCHORED TO)
cast call 0x363582956488ff615ecf75783fedc5adb18ca6d0 "tipHeight()(uint256)"
Trace a real withdrawal end-to-end
This is how the burn-verifier address and the full relay→SP1→Groth16 call sequence were confirmed.
# REPLAY A WITHDRAWAL AND INSPECT THE INTERNAL CALLS
cast run 0x45f7ccbcb1c3dc37cd6b83e1b2c9e26b138d504a9d5a5a537ed432d7264491d9 --quick
Token Cost Breakdown
| PHASE | DESCRIPTION | TOKENS |
|---|---|---|
| Phase 0 | Obtain the Contract | 20 tok |
| Phase 1 | Discovery & Understanding | 35 tok |
| Phase 2 | Deep Dive Analysis | 30 tok |
| Phase 3 | Risk & Trust Analysis | 15 tok |
| Phase 4 | Documentation Generation | 30 tok |
| TOTAL | Complete Contract Analysis | 130 tok |
Note: Token costs are estimates based on typical conversation lengths and complexity. Actual consumption may vary by ±10-15% depending on API responses, iterative refinement, and verification steps.