This document describes the security refactor applied to the smart contract suite for marketplace-enabled CropChain flows (listing, buying, and withdrawing proceeds).
All external state-changing functions follow CEI:
- Checks: input validation, role checks, paused checks, recall checks.
- Effects: storage updates happen before any external calls.
- Interactions: ETH transfers (
refund,withdrawProceeds) occur last.
Functions with external value transfer and strict CEI ordering:
buyFromListingwithdrawProceeds
CropChain inherits ReentrancyGuard and applies nonReentrant on all external, state-mutating entry points:
- admin controls (
setRole,transferOwnership,pause,unpause,setPaused,setTwapConfig) - supply-chain writes (
createBatch,updateBatch,recallBatch) - marketplace writes (
createListing,buyFromListing,cancelListing,withdrawProceeds) - oracle writes (
recordSpotPrice)
Additionally, payout flow uses pull-payments via pendingWithdrawals, reducing direct push-transfer exposure.
Price updates are recorded as timestamped observations:
recordSpotPrice(bytes32 cropTypeHash, uint256 priceWei)
TWAP is calculated over a configurable rolling window:
getTwapPrice(bytes32 cropTypeHash, uint256 windowSeconds)
Marketplace purchases reject listings when listed price deviates beyond configured tolerance from TWAP:
maxPriceDeviationBps(default 1500 bps / 15%)twapWindow(default 1 hour)
Admin can tune risk controls:
setTwapConfig(uint256 twapWindowSeconds, uint256 maxDeviationBps)
Contract inherits Pausable with owner-triggered controls:
pause()unpause()setPaused(bool)(compatibility helper)
All critical write paths are protected by whenNotPaused, allowing immediate containment during incident response.
A dedicated attacker contract (contracts/mocks/ReentrancyAttacker.sol) attempts to re-enter withdrawProceeds() from receive() during payout.
Expected result:
- first withdrawal succeeds
- re-entrant call fails due to
ReentrancyGuard - no double-withdrawal occurs
Test file:
test/security.refactor.test.js
Run from repository root after dependencies are installed.
npm run compile
npm run test
slither ./contracts/CropChain.sol
myth analyze ./contracts/CropChain.sol- Oracle integrity remains an operational trust assumption. Use decentralized oracle infrastructure in production.
- TWAP mitigates single-block price manipulation but does not eliminate cross-window manipulation by privileged oracles.
- Pausing is owner-controlled; secure owner key management (multisig + hardware-backed signer) is required for production.