CaliburProp Info

TBA

CaliburProp Logo

TrustNet Score

The TrustNet Score evaluates crypto projects based on audit results, security, KYC verification, and social media presence. This score offers a quick, transparent view of a project's credibility, helping users make informed decisions in the Web3 space.

47.90
Poor Excellent

Real-Time Threat Detection

Real-time threat detection, powered by Cyvers.io, is currently not activated for this project.

This advanced feature provides continuous monitoring and instant alerts to safeguard your assets from potential security threats. Real-time detection enhances your project's security by proactively identifying and mitigating risks. For more information, click here.

Security Assessments

Select the audit
"Static Analysis Dynamic Analysis Symbolic Execution SWC Check Manual Review"
Contract address
N/A
Network N/A
License N/A
Compiler N/A
Type N/A
Language Solidity
Onboard date 2026/05/06
Revision date 2026/05/06

Summary and Final Words

No crucial issues found

The contract does not contain issues of high or medium criticality. This means that no known vulnerabilities were found in the source code.

Contract owner cannot mint

It is not possible to mint new tokens.

Contract owner cannot blacklist addresses.

It is not possible to lock user funds by blacklisting addresses.

Contract owner cannot set high fees

The fees, if applicable, can be a maximum of 25% or lower. The contract can therefore not be locked. Please take a look in the comment section for more details.

Contract cannot be locked

Owner cannot lock any user funds.

Token cannot be burned

There is no burning within the contract without any allowances

Ownership is not renounced

The owner retains significant control, which could potentially be used to modify key contract parameters.

Contract is upgradeable

The contract uses a proxy pattern or similar mechanism, enabling future upgrades. This can introduce risks if the upgrade mechanism is not securely managed.

Scope of Work

This audit encompasses the evaluation of the files listed below, each verified with a SHA-1 Hash. The team referenced above has provided the necessary files for assessment.

The auditing process consists of the following systematic steps:

  1. Specification Review: Analyze the provided specifications, source code, and instructions to fully understand the smart contract's size, scope, and functionality.
  2. Manual Code Examination: Conduct a thorough line-by-line review of the source code to identify potential vulnerabilities and areas for improvement.
  3. Specification Alignment: Ensure that the code accurately implements the provided specifications and intended functionalities.
  4. Test Coverage Assessment: Evaluate the extent and effectiveness of test cases in covering the codebase, identifying any gaps in testing.
  5. Symbolic Execution: Analyze the smart contract to determine how various inputs affect execution paths, identifying potential edge cases and vulnerabilities.
  6. Best Practices Evaluation: Assess the smart contracts against established industry and academic best practices to enhance efficiency, maintainability, and security.
  7. Actionable Recommendations: Provide detailed, specific, and actionable steps to secure and optimize the smart contracts.

A file with a different Hash has been intentionally or otherwise modified after the security review. A different Hash may indicate a changed condition or potential vulnerability that was not within the scope of this review.

Final Words

The following provides a concise summary of the audit report, accompanied by insightful comments from the auditor. This overview captures the key findings and observations, offering valuable context and clarity.


Smart Contract Analysis Statement

Contract Analysis

The EvaluationVault contract implements a UUPS-upgradeable evaluation-fee collector. Each user is assigned a CREATE2-derived BeaconProxy as their personal deposit address, and a validator role sweeps fees out of those addresses while a deduplication map prevents the same evaluation from being charged twice. A V3 variant adds a gasless path through EIP-3009 transferWithAuthorization. The overall design is clean and well aligned with how hosted-deposit collection patterns are usually built.

This statement reflects the V3 re-audit round. The previously reported items have been addressed as follows:

  • The WITHDRAWER_ROLE.withdraw entry point that previously allowed any holder of the role to drain the vault has been neutralized in V3 by overriding the function to revert with "Deprecated", so a grant of the role no longer has any callable effect.
  • The refundNativeDepositTo path now rejects a zero recipient at the vault entry point before delegating to the deposit proxy, closing the previously reported admin-typo loss vector.
  • The unbounded gas-subsidy parameter and the validator-chosen evaluationSeed item are acknowledged by the project as design choices. The subsidy is configured at approximately $0.2 per collection, and both the role that can change the subsidy and the role that receives it are internal trusted roles operated by the project. Distinct evaluationSeed values intentionally represent distinct purchases by design.
  • The bootstrap function acceptDepositAddressBeacon still writes the beacon pointer after invoking acceptOwnership on the caller-supplied beacon address. The function is admin-only and one-shot, and the residual risk in the current code is informational; the recommendation to apply Checks-Effects-Interactions remains open for a future revision.

Ownership Privileges

The ownership of the contract has been organised through OpenZeppelin's AccessControlEnumerable rather than a single Ownable address. The DEFAULT_ADMIN_ROLE plus three role-specific holders (UPGRADER_ROLE, VALIDATOR_ROLE, WITHDRAWER_ROLE) are all granted to the deployer-supplied admin at initialize time. The admin retains full privileges including:

  • Adding or removing supported tokens and setting the per-token gas-subsidy.
  • Pausing and unpausing the contract.
  • Replacing the deposit-address beacon implementation, which affects every existing per-user deposit proxy in one go.
  • Withdrawing collected fees to any address through withdrawTo and rescuing tokens or native assets stuck at deposit addresses.
  • The admin cannot mint or create tokens within the vault.
  • The admin cannot bypass pause for collect, collectEIP3009, or withdraw.
  • The admin cannot directly siphon a user's per-deposit funds without producing a refundDepositTo event, which is on-chain observable.
  • Cross-chain replay of EIP-3009 signatures is impossible because the underlying token's domain separator includes the chain id.

Security Features

The contract implements several positive security features:

  • nonReentrant on every state-changing externally-callable function plus pause coverage on the collect and withdraw paths.
  • A two-step beacon-ownership transfer using UpgradeableBeacon2Step (Ownable2Step), which prevents the vault from accidentally accepting a half-transferred beacon.
  • A deduplication map keyed by keccak256(userId, evaluationSeed) that prevents the same evaluation from being collected twice.
  • Implementation contracts call _disableInitializers in the constructor, blocking the well-known proxy front-running attack on initialize.

Note - This audit report consists of a security analysis of the EvaluationVault smart contract along with its tightly-coupled dependencies DepositAddressImpl and UpgradeableBeacon2Step. This analysis did not include economic analysis of the contract's tokenomics. Other contracts associated with the project (Payout, ReferralRegister, ReferralClaimer) are covered in separate reports. We recommend investors do their own research before integrating with the contract.

Files and details

Functions
public

/

State variables
public

/

Total lines
of code

/

Capabilities
Hover on items

/

Functions
public

/

State variables
public

/

Total lines
of code

/

Capabilities
Hover on items

/

Functions
public

/

State variables
public

/

Total lines
of code

/

Capabilities
Hover on items

/

Functions
public

/

State variables
public

/

Total lines
of code

/

Capabilities
Hover on items

/

Functions
public

/

State variables
public

/

Total lines
of code

/

Capabilities
Hover on items

/

Findings and Audit result

low Issues | 4 findings

Resolved

#1 low Issue
WITHDRAWER_ROLE.withdraw is a now-unused power that always pays the role holder
EvaluationVaultV3.sol
L81-83
Description

Withdraw lets any holder of WITHDRAWER_ROLE pull amount of token to msg.sender. The original design seems to have anticipated ReferralClaimer pulling fees through this hook, but the current ReferralClaimer is funded by direct ERC-20 transfers and never calls vault.withdraw. The role therefore existed only as a latent backdoor; an accidental or malicious grantRole(WITHDRAWER_ROLE, x) would drain the vault to that address whenever the contract is not paused.

Acknowledged

#2 low Issue
Validator-chosen evaluationSeed enables benign double-billing under operator mistakes
EvaluationVault.sol
L172-195
Description

evaluationSeed is a free input chosen by the off-chain validator. If the back-end accidentally generates two distinct seeds for what is logically the same evaluation, both can be collected as long as the deposit address still holds enough funds. Users are protected by the deposit balance running out, but operationally a buggy validator could over-collect from any user that happens to keep funds at the deposit address.

Resolved

#3 low Issue
transferNative lacks a zero-address check
EvaluationVaultV3.sol
L67-77
Description

The low-level call to address(0) does not revert on most clients; it forwards the value and the ETH is irrecoverable. Admin could previously issue refundNativeDepositTo with to set to the zero address and the call succeeded.

Acknowledged

#4 low Issue
Unbounded admin-set gasSubsidy / fee per supported token
EvaluationVault.sol
L106-111
L172-195
Description

setSupportedToken accepts any gasSubsidy with no upper bound. On every collect the validator caller receives gasSubsidy from the vault and the vault keeps amount minus gasSubsidy. The only sanity check is that amount must exceed gasSubsidy. An admin can therefore configure the subsidy at any percentage of the typical collected amount, including more than 25%. The subsidy is also denominated in absolute token units, so the same numeric value miscalibrates across tokens with different decimals.

optimization Issues | 3 findings

Pending

#1 optimization Issue
Use custom errors instead of revert strings
EvaluationVault.sol
L67-185
Description

Every require uses a string literal. Custom errors are cheaper at deploy time and on revert, and let consumers decode the error structurally.

Pending

#2 optimization Issue
Loop counter optimisation in getAllTokens
EvaluationVault.sol
L292
Description

for (uint256 i = 0; i < length; i++) uses a postfix increment with checked arithmetic, and reads _supportedTokens.at(i) twice per iteration.

Pending

#3 optimization Issue
Constructor non-payable
EvaluationVault.sol
L61
Description

The implementation constructor is non-payable. Implementations are not deployed with value so a payable constructor is harmless and slightly cheaper.

informational Issues | 9 findings

Pending

#1 informational Issue
Checks-Effects-Interactions ordering on acceptDepositAddressBeacon
EvaluationVault.sol
L79-85
Description

acceptDepositAddressBeacon calls beacon_.acceptOwnership() on a caller-provided beacon address before writing depositAddressBeacon = beacon_. The function is gated by DEFAULT_ADMIN_ROLE and is one-shot, but the order violates Checks-Effects-Interactions and Slither plus Aderyn flag it as a reentrancy risk.

Pending

#2 informational Issue
Dedup flag set before the actual sweep (readability)
EvaluationVault.sol
L186-189
Description

The collected[collectKey] = true write happens before DepositAddressImpl.transfer is invoked. If the transfer reverts the entire transaction reverts so the flag is rolled back, but reading the function in source order suggests the dedup write is durable across partial failures, which it is not.

Acknowledged

#3 informational Issue
Self STATICCALL via this.isTokenSupported in collectEIP3009
EvaluationVaultV3.sol
L40
Description

collectEIP3009 issues an external STATICCALL to the proxy itself instead of reading the internal EnumerableSet. This costs an extra ~2600 gas per call and makes V3 inconsistent with V1, which uses the internal access pattern.

Pending

#4 informational Issue
Dead helpers _usdToToken and _tokenToUsd
EvaluationVault.sol
L122-137
Description

Two internal helpers convert between token-native and 18-decimal USD amounts. They are never called inside the vault; both Slither and Aderyn flag them as dead code.

Pending

#5 informational Issue
abi.encodePacked finding on getDepositAddress is a false positive
EvaluationVault.sol
L143-151
Description

Aderyn flags the abi.encodePacked of creationCode plus abi.encode arguments as a hash-collision risk. The encoded blob is the constructor calldata for CREATE2, not the input to a hash function, and the inner abi.encode already pads the constructor argument to 32 bytes. The salt itself uses abi.encode, which is collision-safe.

Pending

#6 informational Issue
acceptDepositAddressBeacon mutates state without an event
EvaluationVault.sol
L79-85
Description

The bootstrap of depositAddressBeacon is a one-shot state change that sets the trust anchor for every deposit proxy. There is currently no event to observe the change off-chain.

Pending

#7 informational Issue
Storage-gap sizing is asymmetric across the suite
EvaluationVault.sol
L301
Description

EvaluationVault reserves __gap of 50 plus 5 used slots, totalling 55. Payout reserves 49 plus 5, totalling 54. ReferralClaimer reserves 45 plus 7, totalling 52. The differences are harmless on a fresh deploy but inconsistent.

Pending

#8 informational Issue
Unbounded loop in getAllTokens is admin-bounded
EvaluationVault.sol
L288-296
Description

getAllTokens iterates over _supportedTokens.length without an upper bound. The list is admin-controlled so DoS by an external party is not realistic, but a hostile or careless admin could grow the list to a size that breaks clients that read this view.

Pending

#9 informational Issue
Halmos symbolic verification skipped due to OZ 5.x ERC-7201 storage
test/halmos/HalmosEvaluationVault.t.sol
L1
Description

Halmos 0.3.3 cannot find a successful path through setUp once any __init function on an OpenZeppelin Upgradeable v5 module is invoked, because of the ERC-7201 namespaced storage layout combined with the Initializable address(this).code.length check. Properties for the vault are exercised by the concrete-EVM tools and the Foundry invariants instead.