Frequently Asked Questions
What is the difference between an upgradeable and immutable contract?
An immutable contract's code is fixed at deployment — it cannot be changed, and there is no admin key that controls it. This maximises trustlessness and eliminates admin key risk, but means bugs cannot be patched. An upgradeable contract uses a proxy pattern — users interact with a proxy address, and the underlying logic contract can be replaced. This allows bug fixes but introduces admin key risk: whoever controls the upgrade key controls the entire contract's behaviour. The choice is not which is "better" but which risk profile matches your system.
When should we use a proxy pattern?
Use a proxy pattern when: the business logic is complex enough that the probability of a post-deployment bug is meaningful, the system holds enough value that a patch-and-upgrade cycle is preferable to a full redeployment, and you can design a governance mechanism for the upgrade key that is as secure as the contract itself. Do not use a proxy pattern as a default — immutable contracts are simpler, cheaper and more trustworthy for use cases where upgrade capability is not genuinely needed.
How do you test smart contracts?
We use a three-layer testing approach: unit tests for individual functions (Hardhat or Foundry), integration tests for multi-contract interactions and external system integration (Hardhat), and property-based fuzz tests for invariants (Foundry + Echidna). The fuzz tests are the most valuable — they test the things you didn't think to write unit tests for. We also run Slither static analysis on every commit and perform manual code review before any audit engagement.
What does a smart contract audit involve?
A third-party audit involves manual code review by security researchers specifically looking for: reentrancy, access control gaps, arithmetic errors, oracle manipulation, logic errors in business rules and design-level issues that automated tools miss. Auditors work from the codebase, the natspec documentation and the invariant definitions. A well-prepared codebase — high test coverage, clear documentation, no outstanding TODOs — gets better audit results. Audits find fewer issues when the internal review is thorough.
How do you handle access control in a multi-role system?
We use OpenZeppelin AccessControl as the base pattern for most multi-role systems — it allows granular role definitions, role admin hierarchies and role revocation. Privileged roles (minting, pausing, upgrading) are assigned to multi-sig addresses rather than EOAs. Timelocks are added to roles that control high-stakes operations. The access control model is defined explicitly before implementation begins, with a role table that maps every sensitive function to the roles that can call it.
What is the difference between Solidity and Rust for smart contracts?
Solidity targets the EVM (Ethereum, Polygon, Arbitrum, etc.) — the largest ecosystem, most tooling and most auditors. Rust (via Anchor) targets Solana — account-based programming model, high throughput, cheaper transactions but different mental model and fewer security tools. CosmWasm (Rust) targets Cosmos chains. The choice is chain-driven, not preference-driven. For most products, EVM + Solidity is the right default because of ecosystem depth. Solana makes sense for high-throughput use cases that the EVM cannot service at acceptable cost.
What gas costs should we expect?
On Ethereum mainnet, a simple ERC-20 transfer costs 21,000–65,000 gas (~$1–10 at $30/ETH and 10 gwei). A complex DeFi interaction (AMM swap, lending deposit) costs 100,000–500,000 gas ($3–50+). Contract deployment costs 1–5M gas depending on size. On L2s (Arbitrum, Base, Optimism) costs are typically 10–100x lower. Gas estimation is part of every architecture decision — a contract that costs $50 per operation has a hard ceiling on its usable market.
How do you handle contract versioning?
For immutable contracts, versioning means coordinated migration — new contract deployment, state migration (if needed) and updating all dependent systems to point to the new address. For upgradeable contracts, versioning is managed through the upgrade process with changelogs, storage layout verification and governance approval. We maintain deployment registries that track contract addresses, versions and upgrade history for all production deployments.
What is the Diamond pattern?
The Diamond pattern (EIP-2535) uses a single proxy address that delegates calls to multiple "facet" contracts based on function selector routing. Each facet handles a subset of functions, and facets can be added, replaced or removed independently. This eliminates the 24KB contract size limit and allows per-function upgrade granularity. The trade-off is significant complexity — storage layout across facets must be carefully managed, and auditing a Diamond system requires understanding the entire facet graph. We use Diamond for large, complex protocol contracts where the modularity justifies the complexity.
How long does a smart contract project take?
A single well-specified contract with full test coverage and internal security review: 2–4 weeks. A multi-contract system (e.g., token + vesting + governance): 4–8 weeks. A full DeFi protocol with audit: 12–20 weeks. Timeline is dominated by the design and testing phases, not implementation. Contracts that skip design or compress testing to ship faster are the ones that result in exploits. We scope every engagement with the assumption that the design phase takes at least as long as the implementation.