Security Audit Report
Comprehensive security assessment of the AgoraX smart contract using manual review with entry-point analysis and invariant-based methodology.
Contract Audited — Suitable for Production
No critical or high severity issues found. 196 tests passing across unit, fuzz, invariant, attack vector, and security audit test suites. The contract demonstrates mature security practices.
Audit Overview
Contract
AgoraX.sol
Solidity Version
^0.8.17
Audit Date
February 2026
Methodology
Entry-point & invariant analysis
0
Critical
0
High
2
Medium
5
Low
3
Informational
Security Features Analysis
| Feature | Implementation | Assessment |
|---|---|---|
| Reentrancy Protection | ReentrancyGuard on all state-changing externals | Strong |
| Access Control | Ownable2Step for two-step ownership transfer | Strong |
| Token Transfer Safety | SafeERC20 for deposits; graceful failure for withdrawals | Strong |
| Integer Overflow Protection | Solidity 0.8+ automatic checks + Math.mulDiv | Strong |
| Fee-on-Transfer Detection | Balance diff checks on all token deposits | Strong |
| MEV Protection | Configurable cooldown period (20s–86400s) | Adequate |
| Non-Transferable Receipts | AGX transfer/approve/transferFrom all disabled | Strong |
| Graceful Failure Handling | Individual token failures in proceeds collection don't block other tokens | Strong |
| Selective Recovery | collectProceedsByToken for targeted single-token retry | Strong |
| Pause Mechanism | Admin can pause new orders/fills; cancel/collect still work | Strong |
Test Coverage
137
Unit Tests
5
Fuzz Tests
4
Invariant Tests
10
Attack Vector Tests
40
Security Audit Tests
196
Total Passing
AGX Token Invariant Analysis
AGX receipt tokens are minted 1:1 with sell amounts and burned during proceeds collection and cancellation. All invariants verified:
Protocol Fee Analysis
The min(creationFee, currentFee) pattern ensures fairness — orders lock in the fee rate at creation time, and users always pay the lower of the two rates.
| Scenario | Behavior | Verified |
|---|---|---|
| Fee lowered after order placement | Uses lower current fee | |
| Fee raised after order placement | Uses lower creation fee | |
| Zero protocol fee | No fee deducted | |
| Zero listing fee | Orders accepted with no payment |
Access Control Analysis
Owner Capabilities
| Function | Risk Level | Notes |
|---|---|---|
| addTokenAddress() | Medium | Can whitelist tokens |
| setTokenStatus() | Medium | Can enable/disable tokens |
| pause() / unpause() | Medium | Emergency stop |
| updateFeeAddress() | Low | Fee collection address |
| updateCooldownPeriod() | Low | Bounded 20-86400s |
| updateListingFee() | Low | Bounded by immutable cap |
| updateProtocolFee() | Low | Bounded by immutable cap |
| cleanInactiveUsers() | Low | Maintenance only |
Owner Restrictions
The owner cannot:
- Withdraw user funds
- Modify existing orders
- Change fee caps (immutable)
- Transfer receipt tokens
- Access funds during pause
Two-Step Ownership: The contract uses Ownable2Step requiring the current owner to propose a new owner, who must then accept. This prevents accidental ownership transfer and single-transaction ownership hijacking.
Detailed Findings
Unfillable Dust Orders via Strategic Partial Fills
Due to integer rounding in fill calculations, an attacker could strategically partial-fill an order to leave a remainder smaller than the minimum fillable amount, making the order unfillable.
Mitigation: The allOrNothing flag provides opt-in protection for users concerned about dust attacks. Economic impact is limited to gas costs for cancellation, an acceptable trade-off for supporting partial fills.
Front-Running Cancellation Griefing
An attacker could front-run a cancellation transaction with a fill using a problematic token. Graceful failure handling in proceeds collection mitigates the worst-case scenario — the user still receives their sell token refund and working token proceeds.
Mitigation: Impact is limited: user receives unwanted proceeds tokens + partial refund instead of full refund. Inherent to public mempool visibility, not specific to AgoraX.
No Minimum Order Size Allows Order Book Pollution
There is no minimum order size, theoretically allowing order book pollution with very small orders.
Mitigation: The listing fee (e.g., 100 PLS) acts as an economic deterrent, making spam attacks economically unfeasible.
Cooldown Upper Bound of 24 Hours
The maximum cooldown period of 86,400 seconds (24 hours) could theoretically be used to DOS the protocol by a compromised admin.
Mitigation: Two-step ownership transfer (Ownable2Step) prevents accidental admin changes. Normal operation uses short cooldowns (e.g., 60 seconds). Intentional design range.
validOrderID Modifier Allows Order ID 0
The validOrderID modifier checks _orderID <= orderCounter but does not reject _orderID == 0. Since order IDs start at 1, ID 0 is never valid. All functions with validOrderID have additional checks that reject order 0, so there is no direct security impact.
Mitigation: No exploitable impact. getOrderDetails(0) reverts with array out-of-bounds rather than a descriptive message. Minor code clarity issue.
cleanInactiveUsers Swap-and-Pop Affects Pagination
cleanInactiveUsers uses a swap-and-pop algorithm to remove inactive users, which reorders the allUsersWithOrders array. If called between paginated findFillableOrders queries, some users may be skipped or double-counted.
Mitigation: Affects frontend pagination consistency only. No fund safety impact. Frontend can re-query from the beginning after cleanup.
Low-Level Call to Non-Existent Token Treats Empty Return as Success
The graceful failure pattern uses low-level call for ERC20 transfers. If a token contract self-destructs, the EVM returns success = true with empty returndata. The code treats empty return data as success (to support old-style tokens like USDT), which could zero out state without transferring tokens.
Mitigation: Requires a whitelisted token to self-destruct — extremely unlikely. SELFDESTRUCT is deprecated post-Dencun (EIP-6780). Whitelist is owner-controlled, limiting exposure.
Fee Address Can Block Protocol if Misconfigured
If the fee address is set to a contract that rejects PLS transfers, listing fee payments would fail, blocking new order creation.
Mitigation: The updateFeeAddress function provides an escape hatch for fee address issues.
Rebase Token Limitations
Rebase tokens are not explicitly handled. Positive rebases lock extra tokens with no withdrawal mechanism. Negative rebases may cause cancellation refunds or proceed transfers to fail if the contract balance dropped.
Mitigation: Fee-on-transfer detection does not catch asynchronous rebase behavior. Avoid whitelisting known rebase tokens.
Sell Token Not Validated Against Whitelist
placeOrder validates buy tokens against the whitelist but does not validate the sell token. Any ERC20 can be used as a sell token. This is a design choice — the sell token is provided by the order creator, and buyers choose whether to fill.
Mitigation: Intentional design decision. The listing fee acts as a spam deterrent.
Key Constants
| Constant | Value | Purpose |
|---|---|---|
| PERCENTAGE_DIVISOR | 10000 | Basis points denominator |
| NATIVE_ADDRESS | 0xEeee...eEEE | PLS sentinel address |
| Batch limit | 50 | Max items per batch operation |
| Cooldown bounds | 20–86400 | Seconds (20s to 24h) |
Recommendations Summary
| Priority | ID | Recommendation |
|---|---|---|
| Consider | L-03 | Add _orderID > 0 check to validOrderID modifier |
| Consider | L-05 | Add extcodesize check before low-level transfer |
| Document | L-04 | Note pagination impact of cleanInactiveUsers |
| Document | I-02 | Document rebase token limitations |
| By Design | M-01 | Dust orders — allOrNothing flag mitigates |
| By Design | M-02 | Front-run cancellation — mitigated by graceful failure |
| By Design | L-01 | No minimum order size — listing fee deters spam |
| By Design | L-02 | Cooldown upper bound — intentional range |
Conclusion
No Critical or High severity findings were identified. The contract demonstrates mature security practices with comprehensive protections:
- ✓ Reentrancy Protection
- ✓ Transfer Verification
- ✓ Cooldown Mechanism
- ✓ Graceful Failure Handling
- ✓ Immutable Fee Caps
- ✓ No Oracle Dependency
- ✓ Two-Step Ownership
- ✓ Non-Transferable Tokens
- ✓ Selective Proceeds Recovery
- ✓ Fee-on-Transfer Detection
The contract is suitable for production deployment. The remaining Low-severity recommendations (L-03, L-04, L-05) are quality improvements that can be addressed at the team's discretion. Users should be aware of the dust order edge case (use allOrNothing for protection) and understand that the listing fee serves as anti-spam protection.