Parity Finance Liquid Staking & Early Purchase

QuantstampFiles named in the report

Quantstamp reviewed Parity Finance Liquid Staking & Early Purchase on 3 Jun 2025: 32 findings, 0 critical; 22 marked fixed, 10 open.

No open critical findings
Open the reportOpen Parity Finance Liquid Staking & Early Purchase’s security record

Report hosted on certificate.quantstamp.com.

Trustblock does not review code.

Findings32

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

SeverityOpenAcknowledgedFixed
Critical000
High006
Medium207
Low809
MediumImproper Sale Parameter ValidationOpen

The `early-purchase` program includes `Sale` initialization and update instructions. These instructions lack parameter validation, allowing arbitrary updates of the sale properties that may prevent purchases or harm users. For example, it is possible to set: - A too early or too late start date. - Extremely short, extremely long or instantly ending sale. - A Sale with impossible conditions (e.g., `max_tokens_per_user` > `max_tokens_total`). - Zero or too small token price. - Too permissive max price feed age, allowing potential stale prices. - Arbitrary ID values that may have any off-chain implications (e.g., long). - Uninitialized purchase and payment mint accounts (`is_initialized` is not checked). - A zero `max_price_feed_age` which will limit users to only be able to purchase tokens in the same slot a the price feed has been updated which may cause purchase transactions to revert.

MediumMissing/limited Test Suite in Liquid Staking ProgramOpen

The Liquid Staking program appears to have a very limited test suite - there are several unimplemented tests marked with "-" as can be observed in the Test Suite Results section of this report. Contracts that are not extensively tested are at high risk of serious bugs that can impact the protocol's proper functioning and security. While audits can help developers to find bugs, they are not a substitute for thorough unit and integration testing.

LowBuyer Funds Can Be Locked by SellerOpen

The sale organizer (acting through a Guardian) is expected to deposit the `sale.purchase_mint` tokens to fulfill the buyers' purchases after the sale ends in the `early-purchase` program. However, the program currently lacks a mechanism for buyers to cancel their purchases or reclaim their payments if the sale organizer fails to deposit the required `sale.purchase_mint` tokens. This scenario could be exploited by a malicious sale creator who attracts buyers with favorable terms but intentionally fails to deposit the promised tokens. The risk is increased if the ability to create sales is open to all users without significant upfront cost or vetting.

LowFee Withdrawal to `UncheckedAccount` Risks Loss of FundsOpen

In `liquid_staking::withdraw_fees::handler()` function the collected `Pair` fees are transferred from the `Pair` fee account to a destination account. However, the `destination_owner` of the destination account is an `UncheckedAccount`, which could potentially be an inaccessible address, resulting in permanently lost fees.

LowImproper Exchange Rate Calculation ValidationOpen

The exchange rate calculation logic has improper validation: - It is not validated that `current_timestamp > self.last_yield_change_timestamp`. A malicious validator can slightly manipulate the current timestamp, resulting in a negative elapsed time. - High `interval_amounts` can lead to overflows and can indicate errors. Consider adding an upper limit for interval amounts. - Perform a checked conversion instead of a silent conversion when the amounts are calculated as `u128` and then cast to `u64`, as calculations with lots of decimals can cause overflows.

LowLack of Input Validation for Default PubkeyOpen

All `Pubkey` values passed in instructions and set by the program logic are not validated against default value.

LowMissing `PDA` Seed and Bump VerificationsOpen

Several instructions within the `early-purchase` program and also in the `liquid-staking` program (specifically the `create_pair` instruction) accept Program-Derived Accounts (PDAs) as inputs without sufficiently verifying their derivation using seeds and bump constraints in the `#[account(...)]` macro. While some accounts may have `has_one` constraints (e.g., guardian `has_one = authority`), this only validates a field within the provided account's data against another account (like a signer). It does not guarantee that the account itself is the unique, canonical PDA expected by the program for the given seeds. Without explicit seeds and bump checks, instructions may be potentially tricked into accepting an unintended account address if that account is owned by the same program and its data can be successfully deserialized into the target struct.

LowMissing Validation for Merkle Root Can Block Account Whitelist ControlsOpen

In `liquid_staking::update_whitelist.handler()`function, an `access_authority` can update the `access_control.merkle_root` value. However, the function lacks validation to prevent setting the `merkle_root` to an array of all zeros. This oversight creates a potential issue which may block any whitelist verification logic (especially if `is_whitelist_enabled` remains enabled). Additionally, since this function modifies critical program state, an event should be emitted for auditability.

LowMultiple Pairs Can Be Initialized with the Same `LST` TokenOpen

LST token PDAs are initialized only using their prefix and symbol as a seed with the `init_if_needed` directive in the `liquid_staking::create_pair::handler()` function. This permits the creation of pairs using the same LST token, despite the fact that these `base_token_mint` tokens in pairs may have different values. This can result in users staking tokens in one pair and submitting a withdrawal request in a different one.

LowPotentially Inconsistent Hashing of Leaf NodesOpen

The `liquid-staking` program implemented the `state::access_control::check_whitelist_access()` function via Merkle proof verification where the leaf node to be verified is created by `solana_program::keccak::hashv(&[user.key().to_string().as_bytes()])`. However, hashing the string representation of a `Pubkey` is non-standard practice, and it can lead to different representations or unexpected results, for example, if different encoding or string conversion is used on the off-chain side.

Contracts in scope

No deployed address is recorded for this audit.

The report names a repository or files. Open the report to see its scope.

Repository and files the report names (436)

  • clients/js/src/generated/liquid_staking/instructions/fundWithdrawalWindow.ts
  • tests/unit-tests/rate-calculations.test.ts
  • programs/early-purchase/src/state/guardian.rs
  • clients/js/src/generated/liquid_staking/instructions/vaultWithdraw.ts
  • clients/js/src/generated/early_purchase/accounts/guardian.ts
  • clients/js/src/generated/liquid_staking/types/authorityType.ts
  • clients/js/src/index.ts
  • clients/js/dist/src/generated/liquid_staking/instructions/index.js.map
  • clients/rust/generated/liquid_staking/instructions/seal_program.rs
  • clients/js/dist/src/generated/liquid_staking/instructions/createAccessControl.js
  • clients/js/dist/src/generated/liquid_staking/instructions/createTokenMetadata.d.ts
  • clients/rust/generated/liquid_staking/instructions/create_withdrawal_window.rs
  • clients/js/dist/src/generated/early_purchase/accounts/receipt.js
  • clients/js/dist/src/generated/early_purchase/shared/index.d.ts
  • clients/js/dist/src/generated/early_purchase/accounts/sale.js
  • clients/js/dist/src/generated/liquid_staking/instructions/fundWithdrawalWindow.js.map
  • programs/liquid-staking/src/state/pair.rs
  • clients/js/src/generated/liquid_staking/errors/index.ts
  • tests/helpers/index.ts
  • programs/early-purchase/src/instructions/deposit_tokens.rs
  • clients/js/yarn.lock
  • clients/js/dist/src/generated/liquid_staking/instructions/initiateAuthorityTransfer.d.ts
  • clients/js/dist/src/generated/liquid_staking/instructions/createTokenMetadata.js
  • clients/js/dist/src/generated/liquid_staking/types/authorityType.d.ts
  • clients/rust/generated/early_purchase/mod.rs
  • clients/js/dist/src/generated/liquid_staking/accounts/accessControl.d.ts
  • clients/js/src/generated/liquid_staking/errors/liquidStaking.ts
  • clients/js/dist/src/generated/early_purchase/instructions/initializeSale.js.map
  • clients/js/src/generated/liquid_staking/instructions/updatePairLimits.ts
  • clients/js/dist/src/generated/liquid_staking/instructions/unsealProgram.js.map
  • clients/js/dist/src/generated/liquid_staking/instructions/initiateAuthorityTransfer.js.map
  • clients/js/dist/src/generated/liquid_staking/accounts/accessControl.js.map
  • programs/liquid-staking/src/instructions/seal_program.rs
  • clients/js/src/generated/early_purchase/errors/index.ts
  • clients/js/README.md
  • clients/js/src/utils/rateCalculations.ts
  • clients/js/dist/src/generated/liquid_staking/accounts/pair.js
  • clients/js/dist/src/utils/merkle.d.ts
  • clients/rust/generated/liquid_staking/types/guardian_operation.rs
  • clients/js/dist/src/generated/liquid_staking/instructions/createPair.js.map
  • clients/js/dist/src/generated/liquid_staking/instructions/updatePairYield.js
  • clients/js/src/generated/liquid_staking/instructions/createTokenMetadata.ts
  • clients/js/dist/src/generated/liquid_staking/instructions/createTokenMetadata.js.map
  • programs/liquid-staking/src/instructions/update_whitelist.rs
  • clients/js/src/generated/early_purchase/instructions/initializeSale.ts
  • tests/unit-tests/withdrawal.test.ts
  • clients/js/dist/src/generated/liquid_staking/errors/liquidStaking.js
  • clients/js/dist/src/generated/liquid_staking/instructions/createWithdrawalWindow.js.map
  • clients/rust/generated/early_purchase/instructions/initialize_sale.rs
  • clients/js/dist/src/generated/early_purchase/instructions/updateSale.d.ts
  • clients/js/dist/src/generated/liquid_staking/instructions/requestWithdraw.js
  • clients/js/dist/src/generated/liquid_staking/types/authorityType.js.map
  • clients/js/dist/src/generated/liquid_staking/shared/index.js.map
  • clients/js/dist/src/generated/liquid_staking/accounts/withdrawalRequest.js
  • clients/js/dist/src/generated/liquid_staking/instructions/vaultWithdraw.d.ts
  • clients/rust/generated/liquid_staking/instructions/create_access_control.rs
  • clients/js/dist/src/generated/liquid_staking/instructions/cancelAuthorityTransfer.js
  • programs/liquid-staking/src/instructions/stake.rs
  • programs/early-purchase/src/state/sale.rs
  • clients/rust/generated/liquid_staking/instructions/swap_lst.rs
  • clients/js/dist/src/generated/early_purchase/errors/earlyPurchase.js.map
  • clients/js/dist/src/generated/liquid_staking/instructions/updatePairLimits.js.map
  • clients/js/dist/src/generated/early_purchase/types/verificationLevel.d.ts
  • clients/js/dist/src/generated/early_purchase/instructions/purchaseTokens.js
  • clients/rust/generated/early_purchase/instructions/initialize_config.rs
  • programs/early-purchase/src/instructions/initialize_guardian.rs
  • clients/js/dist/src/generated/early_purchase/accounts/guardian.js
  • clients/js/dist/src/generated/liquid_staking/instructions/sealProgram.d.ts
  • clients/js/dist/src/generated/liquid_staking/programs/index.d.ts
  • clients/js/dist/src/generated/early_purchase/instructions/updateSale.js
  • clients/rust/generated/early_purchase/accounts/sale.rs
  • programs/liquid-staking/src/state/withdrawal_request.rs
  • clients/rust/generated/liquid_staking/programs.rs
  • programs/liquid-staking/src/instructions/swap_lst.rs
  • clients/rust/generated/early_purchase/types/price_feed_message.rs
  • clients/js/dist/src/generated/liquid_staking/types/index.js
  • clients/js/dist/src/generated/liquid_staking/programs/index.js
  • programs/liquid-staking/src/instructions/fund_withdrawal_window.rs
  • clients/js/dist/src/generated/early_purchase/instructions/index.js.map
  • clients/js/dist/src/generated/liquid_staking/instructions/createWithdrawalWindow.js
  • clients/rust/generated/liquid_staking/shared.rs
  • programs/early-purchase/src/state/receipt.rs
  • clients/js/dist/src/generated/early_purchase/accounts/receipt.d.ts
  • clients/js/src/generated/early_purchase/instructions/redeemReceipt.ts
  • clients/js/dist/src/generated/liquid_staking/instructions/vaultWithdraw.js.map
  • clients/js/dist/src/generated/liquid_staking/instructions/cancelWithdrawalRequest.d.ts
  • clients/js/dist/src/generated/early_purchase/accounts/index.d.ts
  • clients/js/dist/src/generated/liquid_staking/instructions/stake.d.ts
  • clients/rust/generated/liquid_staking/instructions/create_pair.rs
  • clients/js/dist/src/generated/liquid_staking/instructions/manageGuardian.d.ts
  • tests/unit-tests/staking.test.ts
  • programs/liquid-staking/src/instructions/initiate_authority_transfer.rs
  • clients/js/src/generated/liquid_staking/instructions/updatePairYield.ts
  • tests/helpers/accounts.ts
  • package.json
  • clients/js/dist/src/generated/liquid_staking/instructions/requestWithdraw.d.ts
  • clients/js/dist/src/generated/liquid_staking/instructions/updatePairLimits.js
  • clients/js/dist/src/generated/liquid_staking/errors/liquidStaking.js.map
  • clients/rust/generated/liquid_staking/instructions/unseal_program.rs
  • clients/js/dist/src/generated/liquid_staking/instructions/index.js
  • clients/js/dist/src/generated/liquid_staking/accounts/pair.js.map
  • clients/js/src/generated/early_purchase/types/verificationLevel.ts
  • programs/liquid-staking/src/instructions/mod.rs
  • clients/js/src/generated/liquid_staking/instructions/executeWithdraw.ts
  • clients/js/dist/src/generated/liquid_staking/types/index.d.ts
  • scripts/create-pairs.ts
  • clients/js/dist/src/generated/early_purchase/programs/index.d.ts
  • clients/rust/generated/liquid_staking/accounts/withdrawal_window.rs
  • tests/helpers/pairs.ts
  • tsconfig.json
  • clients/js/src/generated/early_purchase/shared/index.ts
  • clients/rust/generated/liquid_staking/errors/mod.rs
  • clients/js/dist/src/generated/early_purchase/types/index.js.map
  • clients/js/dist/src/generated/liquid_staking/instructions/vaultWithdraw.js
  • clients/js/src/generated/liquid_staking/instructions/createPair.ts
  • clients/js/dist/src/generated/early_purchase/index.d.ts
  • clients/rust/generated/early_purchase/instructions/purchase_tokens.rs
  • clients/js/dist/src/generated/liquid_staking/instructions/requestWithdraw.js.map
  • programs/liquid-staking/src/instructions/withdraw_fees.rs
  • programs/liquid-staking/src/state/withdrawal.rs
  • clients/js/dist/src/generated/liquid_staking/programs/index.js.map
  • programs/liquid-staking/src/instructions/request_withdraw.rs
  • programs/liquid-staking/src/instructions/manage_guardian.rs
  • clients/rust/generated/early_purchase/accounts/config.rs
  • clients/js/dist/src/generated/early_purchase/types/saleState.js
  • clients/js/dist/src/generated/liquid_staking/instructions/cancelAuthorityTransfer.d.ts
  • clients/js/dist/src/generated/liquid_staking/index.js.map
  • clients/js/src/generated/liquid_staking/instructions/restakeExpiredWithdraw.ts
  • clients/js/dist/src/generated/liquid_staking/errors/index.d.ts
  • clients/js/dist/src/generated/liquid_staking/programs/liquidStaking.js.map
  • clients/js/src/generated/early_purchase/instructions/initializeGuardian.ts
  • clients/rust/generated/early_purchase/types/mod.rs
  • clients/rust/generated/early_purchase/instructions/end_sale.rs
  • versions.txt
  • clients/js/dist/src/generated/early_purchase/instructions/initializeConfig.d.ts
  • programs/early-purchase/src/instructions/update_guardian.rs
  • clients/js/src/generated/early_purchase/instructions/updateSale.ts
  • programs/early-purchase/Xargo.toml
  • clients/js/dist/src/generated/early_purchase/instructions/updateSale.js.map
  • tests/unit-tests/pair-configuration.test.ts
  • clients/js/src/generated/liquid_staking/instructions/index.ts
  • clients/js/dist/src/generated/liquid_staking/shared/index.d.ts
  • clients/js/dist/src/generated/early_purchase/programs/earlyPurchase.d.ts
  • clients/js/test-import.js
  • clients/js/dist/src/generated/early_purchase/instructions/depositTokens.js
  • programs/liquid-staking/src/types.rs
  • clients/js/dist/src/generated/liquid_staking/instructions/acceptAuthorityTransfer.js.map
  • clients/js/dist/src/utils/merkle.js
  • clients/rust/generated/early_purchase/accounts/mod.rs
  • clients/js/src/generated/early_purchase/instructions/purchaseTokens.ts
  • clients/js/src/generated/liquid_staking/programs/index.ts
  • clients/js/dist/src/generated/liquid_staking/accounts/index.d.ts
  • clients/js/dist/src/generated/liquid_staking/instructions/acceptAuthorityTransfer.js
  • programs/early-purchase/src/instructions/redeem_receipt.rs
  • clients/js/dist/src/generated/liquid_staking/instructions/withdrawFees.js
  • Cargo.lock
  • clients/js/dist/src/generated/early_purchase/instructions/depositTokens.d.ts
  • clients/js/src/generated/early_purchase/index.ts
  • clients/js/dist/src/generated/early_purchase/instructions/initializeGuardian.js.map
  • tests/unit-tests/vault-management.test.ts
  • clients/js/src/generated/early_purchase/accounts/receipt.ts
  • clients/js/dist/src/generated/liquid_staking/accounts/withdrawalRequest.d.ts
  • clients/rust/generated/liquid_staking/instructions/update_pair_yield.rs
  • programs/liquid-staking/src/lib.rs
  • clients/js/dist/src/generated/early_purchase/accounts/config.js
  • clients/js/dist/src/generated/early_purchase/instructions/updateGuardian.d.ts
  • clients/rust/generated/liquid_staking/instructions/vault_withdraw.rs
  • programs/liquid-staking/src/instructions/vault_withdraw.rs
  • clients/rust/generated/liquid_staking/accounts/mod.rs
  • clients/js/dist/src/generated/early_purchase/errors/index.js.map
  • clients/js/dist/src/generated/liquid_staking/instructions/sealProgram.js
  • clients/js/src/generated/liquid_staking/instructions/withdrawFees.ts
  • clients/js/src/generated/early_purchase/accounts/config.ts
  • clients/js/dist/src/utils/rateCalculations.js
  • clients/js/dist/src/index.js
  • clients/rust/generated/liquid_staking/instructions/withdraw_fees.rs
  • clients/js/dist/src/index.js.map
  • programs/liquid-staking/src/u64x64_math.rs
  • clients/js/dist/src/generated/early_purchase/instructions/updateGuardian.js
  • clients/rust/generated/liquid_staking/mod.rs
  • tests/unit-tests/program-sealing.test.ts
  • tests/unit-tests/rates.test.ts
  • clients/js/dist/src/generated/liquid_staking/accounts/pair.d.ts
  • clients/js/dist/src/generated/early_purchase/instructions/updateGuardian.js.map
  • clients/js/dist/src/generated/early_purchase/types/guardianPermissions.js.map
  • tests/unit-tests/whitelist.test.ts
  • gitignore
  • clients/rust/generated/liquid_staking/instructions/close_withdrawal_window.rs
  • clients/js/dist/src/generated/liquid_staking/errors/index.js
  • clients/rust/generated/liquid_staking/instructions/restake_expired_withdraw.rs
  • clients/js/dist/src/generated/early_purchase/accounts/guardian.js.map
  • clients/js/src/generated/liquid_staking/instructions/requestWithdraw.ts
  • clients/js/dist/src/generated/liquid_staking/accounts/withdrawalWindow.js.map
  • clients/js/dist/src/generated/liquid_staking/accounts/withdrawalRequest.js.map
  • tests/unit-tests/token-metadata.test.ts
  • clients/js/dist/src/generated/early_purchase/instructions/purchaseTokens.js.map
  • clients/js/src/generated/early_purchase/instructions/index.ts
  • clients/rust/generated/liquid_staking/instructions/stake.rs
  • clients/js/dist/src/generated/early_purchase/instructions/endSale.d.ts
  • programs/liquid-staking/src/instructions/create_access_control.rs

Part of Parity Finance Liquid Staking & Early Purchase’s security record

Parity Finance Liquid Staking & Early Purchase
Audits2 audits by 1 firmLast audit Jun 2025, by Quantstamp.
Critical findingsNo open critical findingsAcross 2 reports.
Open Parity Finance Liquid Staking & Early Purchase’s security record

Security firm

Quantstamp

236 projects reviewed · 332 reports · latest Oct 2026

See Quantstamp’s audits

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