Neutral Trade security record

As of 24 Oct 2026, Neutral Trade has 2 audit reports by 2 security firms on Trustblock; the latest is by Quantstamp, dated 4 Jul 2025. Those reports list no open critical findings.

Critical findings
No open critical findings
Across 2 reports.
Open the latest report
Your label, live
Get the label for your site

Record last updated . It holds audits and findings, contracts and incidents up to Oct 2026. Trustblock does not review code.

Audits2

Newest first

AuditSecurity firmDateScopeCritical findingsReport
Neutral TradeSecurity firm: QuantstampDate: Scope: Files named in the reportNo open critical findingsOpen · certificate.quantstamp.com
Neutral Trade - Smart Contract AssessmentSecurity firm: HalbornDate: Scope: Not recorded (see the report)No open critical findingsOpen · halborn.com

Findings16

Statuses are the security firm’s own, from each report.

SeverityOpenAcknowledgedFixed
Critical000
High001
Medium002
Low175
HighRefund Calculation Uses Stale Share-Mint TotalNeutral Trade · Quantstamp · 4 Jul 2025Fixed

The `refund_deposit()` function calculates `shares_to_revert` as `user_share_of_pending_deposits * last_total_shares_minted / PRECISION`, yet `bundle_temp_data.last_total_shares_minted` is **never reduced** after each refund. When multiple deposits are refunded in succession, earlier refunds shrink `cumulative_pending_deposits` but leave `last_total_shares_minted` unchanged; later iterations therefore cancel too many shares. The bundle ends with the correct underlying balance but an under‑reported `total_shares`, distorting share price and subsequent accounting. The same stale value is reused in `process_deposits.rs`, compounding the mismatch whenever refunds and new deposits occur in the same cycle.

Open the report
MediumPrecision Loss Due to Division Before MultiplicationNeutral Trade · Quantstamp · 4 Jul 2025Fixed

The current implementation for calculating management fees is susceptible to a loss of precision due to its reliance on sequential integer divisions. This will cause the protocol to undercharge users for management fees over the long term systematically. ```rust let time_fraction = seconds_elapsed .checked_mul(bundle.asset_precision as u128) .ok_or(ErrorCode::MathError)? .checked_div(SECONDS_IN_YEAR) .ok_or(ErrorCode::MathError)?; // calculate fee percentage: (time_fraction * annual_fee_rate) / 10000 let mgmt_fee_pct = time_fraction .checked_mul(annual_fee_rate) .ok_or(ErrorCode::MathError)? .checked_div(10000) // Convert from bps to decimal .ok_or(ErrorCode::MathError)?; ``` The calculation is performed in three steps: A `time_fraction` is calculated, representing the portion of a year that has passed since the last fee collection. This calculation involves a division that truncates any remainder. The `time_fraction` is then used to calculate a `mgmt_fee_pct`, which involves another division and potential truncation. Finally, this percentage is used to determine the `management_fee_shares`. Because integer division in computing discards the remainder, any fractional component is lost at each step. This error, while potentially small for any single calculation, compounds and guarantees that the final fee charged will be less than or equal to the correct amount, but never more. Over thousands of transactions and users, this results in a slow but steady leak of value from the protocol's treasury. This is also the case for the P&L for shares: ```rust let pnl_usd = pnl_per_share .checked_mul(user_bundle_account.shares) .ok_or(ErrorCode::MathError)? .checked_div(bundle.asset_precision as u128) .ok_or(ErrorCode::MathError)?; // Step 2: Second division let perf_fee_usd = pnl_usd .checked_mul(bundle.performance_fee as u128) .ok_or(ErrorCode::MathError)? .checked_div(10000) .ok_or(ErrorCode::MathError)?; // Step 3: Third division performance_fee_shares = perf_fee_usd .checked_mul(bundle.asset_precision as u128) .ok_or(ErrorCode::MathError)? .checked_div(share_price) .ok_or(ErrorCode::MathError)?; ```

Open the report
MediumFirst user allocating funds might drain underlying balanceNeutral Trade - Smart Contract Assessment · Halborn · 21 Jan 2025Fixed

The report gives no description here.

Open the report
LowCode ImprovementNeutral Trade · Quantstamp · 4 Jul 2025Fixed

The code can benefit from the following validations and improvements: 1. Add `withdrawal_fee` to `ChangedCoreParams` and include `cooldown_period` plus `estimated_pending_withdrawal_value` in `WithdrawalRequested`. 2. `new_manager ` instruction is not needed in `change_manager()`, unless `new_manager` is required as additional signer. 3. Drop the unused `oracle_data` account from `set_max_deposit_amount()` or reference it explicitly. 4. Remove the redundant pause check in `end_distribution()`. 5. In `request_withdrawal ()`, since there is an earlier check that estimated pending withdrawls value is zero, it is possible to replace `checked_add()` for `user_bundle_account.estimated_pending_withdrawal_value` with `estimated_withdrawal_amount` with direct assignment. 6. Initialize `user_bundle_account.owner` in `initialize_bundle_depositor()` instead of `request_deposit()`. 7. Delete or annotate unused helpers like `fetch_account_balance()` in `bundle.rs`. 8. Reject `Pubkey::default()` in `change_bundle_master_admin()` to prevent null assignments. 9. Require the treasury to be a valid `TokenAccount` with `mint == asset_address` in all relevant instructions. 10. Declare `treasury_account` as `Account<'info, TokenAccount>` in `request_deposit()`. 11. The `receiver_address` in `add_strategy()` should be checked against the `Pubkey::default()`to prevent null assignments. 12. The `newkeeper` in `set_keeper()` should be checked against the `Pubkey::default()` to prevent null assignments.

Open the report
LowEnabling a Strategy without Prior Removal Can Inflate Bundle AllocationNeutral Trade · Quantstamp · 4 Jul 2025Fixed

The protocol assumes every strategy follows a strict life‑cycle: it is first added, later removed, and only then re‑enabled. The enable_strategy instruction, however, does not verify that `strategy_account.allowed` is currently false. If a bundle manager submits an enable_strategy call while the strategy is still marked as allowed—whether due to a failed or out‑of‑order `remove_strategy` transaction—the function blindly adds `strategy_account.allocation_bps` to `bundle_account.current_allocation_bps` a second time. This double‑counting breaks the bundle’s internal accounting, and may prevent subsequent strategy operations or open unintended allocation imbalances. Although unlikely in normal use, the absence of the guard leaves room for human error or automated scripts that batch transactions without checking intermediate results.

Open the report
LowRefill Uses Stale Oracle Data if Feed Is Out‑of‑dateNeutral Trade · Quantstamp · 4 Jul 2025Fixed

The `perform_refill()` function recomputes equity by adding the refill amount to `oracle_data.average_external_equity`. Yet it never verifies that the oracle price is fresh; if `last_update_time` is well in the past, the function records equity with outdated market data, skewing bundle accounting, share‑price calculations.

Open the report
LowUpdating Allocation of a Disabled Strategy Breaks Bundle AccountingNeutral Trade · Quantstamp · 4 Jul 2025Fixed

The `update_allocation()` function is designed to adjust the position size of an active strategy. Yet the instruction never checks that `strategy_account.allowed` is `true` before proceeding. If a bundle manager calls `update_allocation` on a strategy that has already been removed, the logic becomes harmful: 1. It subtracts the strategy’s previous `allocation_bps` from `bundle_account.current_allocation_bps`, even though that subtraction already occurred during `remove_strategy`. 2. It then adds the new allocation value and writes it to the strategy account. The modification in the bundle's allocation causes it to drift from the correct allocation, potentially turning negative or falling below the real sum of active strategies. Situations that can trigger the bug include: * Managers misunderstanding the life‑cycle and adjusting a removed strategy. * Transaction ordering issues where `remove_strategy` fails but a queued `update_allocation` succeeds.

Open the report
LowInconsistent constraints on manager for multiple entry pointsNeutral Trade - Smart Contract Assessment · Halborn · 21 Jan 2025Fixed

The report gives no description here.

Open the report

Contracts

No deployed address is recorded for these audits.

The reports name a repository or files. Open a report to see its scope.

The repositories and files the reports name

Show this on your site

Is this your project? Show this record on your own website. The label states what the record holds, links to this page and updates by itself. It is free and needs no sign-in.

Content

Facts

Automatic: the three strongest facts of this project’s own record (its last audit and two more), highlighted. They update with the record. Picking a fact turns Automatic off.

Fixed as
Language

Style

Layout
Theme
Accent
Corners

Format

Size
Date
Embed as
HTML
<head>
<script src="https://widget.trustblock.run/project-widget.min.js" defer></script>
</head>
<body>
<div
data-tb-project-widget
data-tb-project-slug="neutral-trade"
></div>
</body>

Paste the code where the label should appear. It uses no API credit and updates by itself.

Something wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.

Tell us