// SECURITY RESOURCES

Smart contract security resources for teams shipping real value.

Original HashEye guidance for founders, engineers, and protocol operators who need practical smart contract security best practices before an audit, during an incident, and at integration time.

> best_practices
> incident_response
> secure_workflow
> token_checklist

[01] resources/best-practices

// HIGH-LEVEL BEST PRACTICES

Make the dangerous paths obvious.

A secure contract starts with a clear map of value, authority, and failure modes. These notes help teams review the design before the codebase grows teeth.

HL-01

Map the value path

fundsstateexits

Write down every place value can enter, move, pause, or leave the system before reviewing code. The dangerous parts are often the transitions: minting, withdrawals, upgrades, keeper calls, bridges, and emergency controls.

Use that map as the review spine. Any function touching value should have an owner, a limit, a failure mode, and a test that proves the intended path still holds under hostile timing.

HL-02

Keep authority narrow

rolestimelocksrotation

Every privileged account should have one job, a delay where users need time to react, and a documented rotation path. If a role can change prices, pause transfers, upgrade logic, or move treasury funds, treat that role as part of the attack surface.

Avoid shared catch-all operators. A compromised signer should not become a master key for minting, custody, configuration, and upgrades at the same time.

HL-03

Prefer explicit invariants

assetsclaimsrounding

A contract should state what must remain true across deposits, withdrawals, liquidations, rewards, and upgrades. Tests should attack those invariants with bad timing, unusual token behavior, and repeated calls from the same address.

Keep invariants short enough for engineers to remember during review. If the rule cannot fit in one sentence, split the design until each risk has a clean owner.

solidity invariant sketch
assert(totalAssets() >= totalUserClaims());
assert(protocolFees <= totalAssets());

[02] resources/incident-response

// INCIDENT RESPONSE GUIDELINES

Move fast without inventing facts.

During an exploit, calm systems beat loud chats. The goal is to reduce loss, preserve evidence, and give users information that can be trusted.

IR-01

Confirm the blast radius

contractsbalancestxs

Start with facts that can be checked on-chain: affected contracts, functions touched, token balances, privileged calls, and suspicious transaction clusters. Keep speculation out of the first record so the team does not chase a story while funds are still moving.

Assign one person to update the incident ledger and one person to challenge each claim. This keeps the response from turning into a pile of screenshots with no source of truth.

IR-02

Stabilize before public detail

pauserevokeroute

Use the smallest control that prevents more loss: pause a market, disable a route, revoke an integration, or move unaffected funds through an approved emergency path. Broad actions can create new damage if they block withdrawals or break dependent contracts.

Publish enough for users to act, but hold exploit mechanics until mitigation is live. A clean status note beats a detailed attacker tutorial while the system is still exposed.

IR-03

Preserve an evidence trail

logsownerstime

Snapshot balances, event logs, contract bytecode, config values, signer lists, and deployment artifacts before repairs change state. The first hour usually contains evidence that will be harder to reconstruct later.

Store decisions with timestamps and owners so later review can separate response speed from guesswork. A postmortem is only useful when it can trace what the team knew at each point.

[03] resources/development-workflow

// SECURE DEVELOPMENT WORKFLOW

Ship through gates, not vibes.

Security work gets cheaper when it is attached to normal engineering flow. The workflow below keeps reviewable facts close to the code that depends on them.

SD-01

Lock scope before review

commitcompilerchain

Freeze contract files, commit hash or archive hash, compiler settings, deployment scripts, and external assumptions before a serious review begins. If code changes mid-review, log the delta and decide whether it is a patch check or a new scope.

A locked scope protects both the protocol and the reviewers. It prevents silent drift where a finding is fixed in one file while a new issue lands nearby without scrutiny.

SD-02

Review design and code together

threatseconomicsusers

A clean implementation can still encode a broken market, reward schedule, or governance path. Pair code review with threat modeling so reviewers test the product promise, not just the syntax.

Design notes should include trusted actors, emergency powers, oracle assumptions, liquidity assumptions, and expected user flows. Missing assumptions are where many real bugs hide.

SD-03

Make releases boring

forksignersrollback

Dry-run deployments on a fork, record expected addresses, verify initializer values, and rehearse rollback steps with the same signers used in production. A release checklist should catch operational mistakes before auditors have to explain them after launch.

Keep deployment artifacts, verification settings, and transaction hashes in one place. Future incident response depends on knowing exactly what was deployed and who approved it.

[04] resources/token-integration

// TOKEN INTEGRATION CHECKLIST

Never trust a token by its interface alone.

Token integrations fail when the caller assumes every asset behaves like the happy-path example. Treat each token as external code with its own authority, accounting, and failure behavior.

TI-01

Normalize token assumptions

decimalsfeescontrol

Before integrating any token, verify decimals, return values, fee-on-transfer behavior, rebasing behavior, pause controls, blacklist controls, and upgrade authority. Do not assume ERC-style names mean ERC-style behavior.

Record these assumptions beside the integration code. When a token changes or a new asset is listed, reviewers need a checklist, not tribal memory.

TI-02

Measure received value

balanceroundingminimum

When a contract accepts tokens, compare balances before and after transfer rather than trusting the requested amount. This protects accounting when tokens burn fees, round amounts, or return unexpected values.

Use minimum received checks where user intent matters. Silent short transfers turn into bad shares, bad debt, or mismatched accounting that can compound over time.

solidity accounting sketch
uint256 beforeBalance = asset.balanceOf(address(this));
asset.safeTransferFrom(msg.sender, address(this), amount);
uint256 received = asset.balanceOf(address(this)) - beforeBalance;
require(received >= minReceived, "short transfer");

TI-03

Contain approvals and custody

limitsexpirymonitoring

Approvals should be limited by amount, purpose, and lifetime wherever the workflow allows it. Infinite approvals are operationally convenient, but they widen the damage from a compromised spender.

Custody contracts need withdrawal paths, signer rotation, and monitoring for token contract changes. If the token owner can pause, upgrade, blacklist, or seize funds, your protocol needs an answer before deposits open.