Smart Contract Development in Solidity

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
Smart Contract Development in Solidity
Medium
~3-5 business days
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1215
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1043
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

Smart Contract Development in Solidity

A client brings a contract for audit — 800 lines of Solidity, deployment to Ethereum mainnet in a week. On the third page of code, a pattern emerges: external call before state update, classic reentrancy. Not theoretical — the same configuration was in The DAO in 2016, $60 million. The contract goes back for rework. This is a standard situation when Solidity development happens without a systematic approach to security.

Where Solidity Contracts Most Often Break

Reentrancy Still Lives in Production

Despite the attack being known since 2016, reentrancy variants continue to appear in production. The problem isn't lack of awareness — most developers know the Checks-Effects-Interactions pattern. The problem is cross-function reentrancy, which ReentrancyGuard from OpenZeppelin doesn't cover by default.

Scenario: Contract A calls Contract B through a low-level call. B is a token implementing ERC-777 with a tokensReceived hook. At the moment of the hook, A has already transferred tokens, but hasn't sent ETH yet. The withdrawal function in A isn't protected by a reentrancy guard because the developer thought they only protected withdraw. Result — account draining.

Solution: nonReentrant on all public functions that modify state and make external calls. For complex systems — a separate ReentrancyGuardUpgradeable with module-level checking instead of per-function.

Storage Collision in Proxy Patterns

With Transparent Proxy or UUPS, variables are stored in storage slots by declaration order. If you add a variable before an existing one in a new implementation — all storage shifts. address public owner becomes garbage, which was previously uint256 public totalSupply.

This isn't hypothetical: several protocols in 2022-2023 discovered the issue after upgrade when mappings started returning wrong values. The solution is ERC-7201 (namespaced storage) — implementation variables are stored at a pre-selected slot through keccak256 hash, isolated from proxy variables.

Gas Griefing via Unbounded Loops

A function that iterates through address[] public users without limits is safe with 50 users and becomes a DoS vector at 5000. The transaction hits the block gas limit and reverts. If this function is critical to the protocol — griefing costs the attacker little, costs the protocol much.

Solution pattern: pagination via offset/limit or pull pattern instead of push (user claims rewards themselves instead of the contract sending to everyone).

How We Write Solidity Contracts

Stack and Tools

The main development tool is Foundry. Not because of hype, but specific capabilities: fuzz-testing directly in tests via vm.fuzz, fork testing on real mainnet state via vm.createFork, and compilation speed 4-5x faster than Hardhat on large projects.

Hardhat remains in the stack for tasks where the plugin ecosystem matters: hardhat-deploy for reproducible deployments, hardhat-gas-reporter for gas reports in CI, TypeChain integration.

Base contracts — OpenZeppelin 5.x. Never fork or modify internals. If extension is needed — inheritance and override with explicit super._call().

Static analysis: Slither on every PR, Mythril for symbolic execution before deployment. For fuzzing complex logic — Echidna with property-based tests.

Patterns We Use

Diamond Pattern (EIP-2535) — for systems where function count exceeds a single contract's bytecode limit (24 KB). Facet architecture allows adding functionality without storage disruption. Used rarely — only where truly needed, due to audit complexity.

Pull payment pattern — ETH is never sent directly from protocol functions. Balances accumulate in a mapping, users call withdraw(). This eliminates an entire class of reentrancy vectors and removes issues with receiver contracts that revert receive().

Multicall — batching transactions via ERC-2771 or custom implementation. Reduces on-chain calls, critical at high mainnet gas.

Gas Optimization

Typical places where gas is wasted:

Pattern Problem Solution Savings
bool variable alone Occupies full slot (32 bytes) Pack in struct with adjacent types 15-20k gas on deploy
storage read in loop Each SLOAD = 100 gas (EIP-2929) Cache in memory before loop Up to 80% on loop
emit Event without indexing Can't filter via The Graph indexed on key fields No gas savings, but critical for DX
string in storage Expensive and inefficient bytes32 for fixed strings 3-5x savings

Reordering variables for slot packing is the first thing we do in gas audits. A contract with uint128 a; uint256 b; uint128 c; occupies 3 slots. Reordering to uint128 a; uint128 c; uint256 b; — 2 slots. On deployment, the difference is 20-40k gas, on each SLOAD in hot paths — noticeable.

Work Process

Analytics (1-3 days). Parse the architecture: roles, rights, invariants the system must always maintain. Invariants are the foundation for property-based tests in Echidna.

Design (2-5 days). Contract diagram, storage layout, interfaces. At this stage we decide on upgradeability: UUPS, Transparent, or immutable. For DeFi protocols with value >1M USD, upgradeability isn't always an advantage from a trust perspective.

Development. Contracts + tests in Foundry. Coverage >95% by line, fuzz tests on all public functions with numeric parameters. Fork tests on Ethereum/Polygon mainnet for Uniswap, Aave, Chainlink integrations.

Internal Audit. Slither, Mythril, manual review with SWC (Smart Contract Weakness Classification) checklist. Doesn't replace external audit but covers low/medium severity before it starts.

Deployment. Scripts via Foundry forge script with auto-verification on Etherscan/Polygonscan. Deploy first to testnet (Sepolia, Mumbai), then mainnet through multisig via Gnosis Safe.

Timeline Estimates

Simple ERC-20 token with basic functions — 3-5 days including tests. Staking contract with rewards and time locks — 1-2 weeks. Full-fledged DeFi protocol with AMM logic or lending — from 6 weeks. Timelines depend on logic complexity and test coverage requirements.

Cost is calculated after analyzing the technical specification.