Quantum Audit Logo

Is Sally Safe?

On-chain security analysis — is it a scam or legit?

Sally A1C
0x1f1c…ad69
Base Not verifiedLast checked 3d ago 1 audit on record
Executive SummaryAI Copilot

The AgentKey contract, an upgradeable ERC20 token with staking and fee distribution mechanisms, leverages OpenZeppelin's secure libraries and reentrancy guards. However, a critical vulnerability was identified where the `_approve` function is called with an incorrect signature, preventing the core fee-swapping functionality. Additionally, the fee distribution logic is susceptible to reentrancy, and Uniswap swaps lack slippage protection, exposing the protocol to significant financial risks. Centralized control points and immutable configuration parameters also present operational and governance considerations.

1 Critical2 High2 Medium1 Low
Volume 24h
$88.6K
Liquidity
$316.2K
Price
$0.1805
Token Age
1y
Top 10 Holders
56.1%

Security Findings

Critical

Critical Vulnerability: Incorrect `_approve` Function Signature

C-01In the `_swapToETH` function, the call `_approve(address(this), address(router), _amount, false)` attempts to approve tokens for the Uniswap router. However, the standard OpenZeppelin `ERC20Upgradeable._approve` function, which this contract inherits, only accepts three arguments (`owner`, `spender`, `value`). The inclusion of a fourth `false` argument results in an incorrect function signature. This will cause a compilation error or, if a custom `_approve` with this signature exists (which is not provided in the standard imports), it would lead to an unintended and potentially insecure behavior. This is a fundamental bug that prevents the core fee-swapping mechanism from functioning correc…
IssueIn the `_swapToETH` function, the call `_approve(address(this), address(router), _amount, false)` attempts to approve tokens for the Uniswap router. However, the standard OpenZeppelin `ERC20Upgradeable._approve` function, which this contract inherits, only accepts three arguments (`owner`, `spender`, `value`). The inclusion of a fourth `false` argument results in an incorrect function signature. This will cause a compilation error or, if a custom `_approve` with this signature exists (which is not provided in the standard imports), it would lead to an unintended and potentially insecure behavior. This is a fundamental bug that prevents the core fee-swapping mechanism from functioning correc…
FixCorrect the `_approve` call to match the standard OpenZeppelin `ERC20Upgradeable._approve` signature: `_approve(address(this), address(router), _amount)`. If a custom `_approve` is intended, its implementation must be provided and thoroughly reviewed.
StatusUnresolved
High

Reentrancy Vulnerability in Fee Distribution

H-01The `_update` function, which is called by `transfer` and `transferFrom`, is not protected by a reentrancy guard. Inside `_update`, if `_to == pair`, it performs a `super._update` call, then calls `_handleFee`, and then another `super._update`. The `_handleFee` function itself is protected by `nonReentrant`, but it makes external calls (`_feeHandler.pay`, `_safeETHTransfer`, `router.swapExactTokensForETH`) between internal state updates. An attacker could re-enter the `transfer` or `transferFrom` function during these external calls, potentially manipulating balances or fees before the full `_update` sequence is completed, leading to double-spending of tokens or incorrect fee calculations.
IssueThe `_update` function, which is called by `transfer` and `transferFrom`, is not protected by a reentrancy guard. Inside `_update`, if `_to == pair`, it performs a `super._update` call, then calls `_handleFee`, and then another `super._update`. The `_handleFee` function itself is protected by `nonReentrant`, but it makes external calls (`_feeHandler.pay`, `_safeETHTransfer`, `router.swapExactTokensForETH`) between internal state updates. An attacker could re-enter the `transfer` or `transferFrom` function during these external calls, potentially manipulating balances or fees before the full `_update` sequence is completed, leading to double-spending of tokens or incorrect fee calculations.
FixApply the `nonReentrant` modifier to the `_update` function or ensure that all external calls are made after all state changes are finalized within the `_update` and `_handleFee` logic. A common pattern is to use a 'checks-effects-interactions' approach.
StatusUnresolved
High

Lack of Slippage Protection in Uniswap Swaps

H-02The `_swapToETH` function executes `router.swapExactTokensForETH` with `minAmountOut` set to `0`. This means the contract accepts any amount of ETH in return for the swapped tokens, regardless of the current market price. This vulnerability exposes the contract to sandwich attacks, front-running, and general price manipulation, where malicious actors can exploit the lack of slippage protection to extract value from the fee collection mechanism, leading to significant financial losses for the protocol.
IssueThe `_swapToETH` function executes `router.swapExactTokensForETH` with `minAmountOut` set to `0`. This means the contract accepts any amount of ETH in return for the swapped tokens, regardless of the current market price. This vulnerability exposes the contract to sandwich attacks, front-running, and general price manipulation, where malicious actors can exploit the lack of slippage protection to extract value from the fee collection mechanism, leading to significant financial losses for the protocol.
FixImplement robust slippage protection by calculating a reasonable `minAmountOut` based on the expected exchange rate and a predefined slippage tolerance. This value should be passed to `swapExactTokensForETH` to ensure that swaps only execute if the received amount of ETH is above a certain threshold.
StatusUnresolved
Medium

Immutability of Critical Configuration Parameters

M-01Several key operational parameters, including `adminSellFeePercent`, `creatorSellFeePercent`, `treasury`, `router`, and `ansTokenID`, are set during the `initialize` function and declared as `public` but without setter functions. This makes them immutable after deployment. While immutability can reduce governance attack surface, it also removes the flexibility to adjust fees in response to market changes, update the treasury address, or change the Uniswap router if a vulnerability or better alternative emerges. This could lead to operational rigidity or necessitate a full contract upgrade for minor parameter adjustments.
IssueSeveral key operational parameters, including `adminSellFeePercent`, `creatorSellFeePercent`, `treasury`, `router`, and `ansTokenID`, are set during the `initialize` function and declared as `public` but without setter functions. This makes them immutable after deployment. While immutability can reduce governance attack surface, it also removes the flexibility to adjust fees in response to market changes, update the treasury address, or change the Uniswap router if a vulnerability or better alternative emerges. This could lead to operational rigidity or necessitate a full contract upgrade for minor parameter adjustments.
FixEvaluate whether these parameters truly need to be immutable. For parameters that might require future adjustments (e.g., fee percentages, treasury address, router address), consider implementing controlled setter functions, possibly with a timelock, to allow for secure updates.
StatusUnresolved
Medium

Centralized Control and Potential Single Points of Failure

M-02The `_factory` and `bondingCurve` addresses hold significant control over the contract's lifecycle and initial operations. `initialize` is restricted to `_factory`, while `launch` and `setPair` are restricted to `bondingCurve`. Additionally, pre-launch `transferFrom` is restricted to `bondingCurve`. If these controlling addresses are compromised, it could lead to unauthorized contract initialization, manipulation of the trading pair, or unauthorized token transfers before launch.
IssueThe `_factory` and `bondingCurve` addresses hold significant control over the contract's lifecycle and initial operations. `initialize` is restricted to `_factory`, while `launch` and `setPair` are restricted to `bondingCurve`. Additionally, pre-launch `transferFrom` is restricted to `bondingCurve`. If these controlling addresses are compromised, it could lead to unauthorized contract initialization, manipulation of the trading pair, or unauthorized token transfers before launch.
FixEnsure that the private keys or multi-signature wallets controlling `_factory` and `bondingCurve` are secured with the highest standards. Consider implementing a multi-signature wallet for these critical roles to distribute control and reduce the risk associated with a single point of failure.
StatusUnresolved
Low

Potential Denial of Service in Fee Distribution

L-01The `_handleFee` function attempts to pay the `adminAmount` to `_feeHandler` via `_feeHandler.pay{value: adminAmount}()`. If the `_feeHandler` contract is malicious, incorrectly implemented, or enters a state where its `pay()` function consistently reverts (e.g., due to an internal error or a block on receiving ETH), it could cause all transfers to the `pair` to fail, effectively halting the fee collection mechanism and disrupting normal token operations.
IssueThe `_handleFee` function attempts to pay the `adminAmount` to `_feeHandler` via `_feeHandler.pay{value: adminAmount}()`. If the `_feeHandler` contract is malicious, incorrectly implemented, or enters a state where its `pay()` function consistently reverts (e.g., due to an internal error or a block on receiving ETH), it could cause all transfers to the `pair` to fail, effectively halting the fee collection mechanism and disrupting normal token operations.
FixImplement robust error handling for external calls. Consider using a `try/catch` block around the `_feeHandler.pay()` call to gracefully handle reverts, perhaps by logging the failure and attempting to send the funds to a fallback address or accumulating them for later manual recovery. Alternatively, ensure `_feeHandler` is a trusted and audited contract.
StatusUnresolved

Category Ratings

TechnicalMedium5/10

The contract leverages OpenZeppelin's `ERC20BurnableUpgradeable` and `ReentrancyGuard` for foundational security, and uses a specific Solidity version (0.8.27). However, a critical bug exists in the `_swapToETH` function where `_approve` is called with an incorrect number of arguments, which would prevent compilation or lead to unexpected behavior (7.2 Code Security). Additionally, the `_update` function, which handles token transfers and fee collection, is susceptible to reentrancy due to external calls within its execution flow (7.2 Code Security), and the Uniswap swap lacks slippage protection, exposing the protocol to significant value loss from front-running and sandwich attacks (7.4 Economic).

GovernanceHigh3/10

The contract's economic model includes a subscription/cooldown mechanism and a fee distribution system. Key parameters like fee percentages (`adminSellFeePercent`, `creatorSellFeePercent`) and the `treasury` address are immutable after initialization, which limits flexibility for future adjustments (7.4 Economic). Initial contract setup and critical operations like `launch` and `setPair` are controlled by specific `_factory` and `bondingCurve` addresses, introducing centralization risks (7.3 Access Control, 7.5 Governance).

UpgradesHigh1/10

The contract is designed as an upgradeable implementation using OpenZeppelin's `ERC20BurnableUpgradeable` and the `initializer` modifier, following standard proxy patterns. Immutable variables are correctly set in the constructor, while mutable state is handled in `initialize`. No immediate upgrade safety issues were identified, but the immutability of certain configuration parameters (e.g., fee percentages) means that any changes to these would necessitate a full contract upgrade, rather than a simple parameter adjustment (7.7 Upgrades).

Security Checklist

Contract VerifiedPass
Ownership Renounced?
No Mint FunctionPass
Liquidity LockedPass
Not a ProxyFail
HoneypotNoneBuy Tax0.0%Sell Tax0.0%

Proxy Upgrade Controls

Proxy TypeEtherscan Detected Custom
ImplementationVerified source
Upgrades (30d)0 · stable

Holder Composition

9.3% in wallets46.8% in contracts
Effective Concentration28.1%

Share held by contracts — treasury, vesting, bridge or staking — is discounted against share held by wallets when the score is computed: a contract cannot decide to sell the way an anonymous holder can, though it can still be drained or voted to sell. Effective concentration is the figure the risk score is actually calculated from.

Liquidity Depth

The risk score reads depth across every pair. The volume figure and the volume-to-liquidity ratio elsewhere on this page describe only the pair this audit analysed, so the two are not directly comparable.

LP Distribution

LP Burned100.0% · ≈ permanent lock
LP Locked100.0% · Null Address

Key Addresses

Deployer
0x675d…d25e
Unlocked LP Held By
0x16aa…7e1b0xd5fd…b81c0x2ee5…5e36

No privileged address appears among these holders: the unlocked liquidity sits with independent providers, not with the deployer.

What Raised This Score

  • Ownership status UNKNOWN (owner could not be resolved)
  • Proxy contract (upgradeable — admin can replace logic)
  • Non-standard proxy storage (Etherscan-confirmed)
  • Top-10 concentration > 20% (56.1% total → 28.1% effective; 9.3% in EOAs, 46.8% in contracts — mild)
  • 1 Critical finding(s) from audit
  • 2 High finding(s) from audit
  • 2 Medium finding(s) from audit
  • 1 Low finding(s) from audit

Each factor is an on-chain fact recorded at the time of this analysis. The score is computed from them by a deterministic function, so the same contract returns the same score for anyone who runs the audit. How scores are computed

Related Audits

AUTONOMOPOLY (AUTONO)High RiskSolana (SOL)High RiskTAOTHigh RiskCheckmate (CHECK)High RiskSoSoValue (SOSO)High RiskHOMEHigh Risk

Would You Like a More Detailed Audit of Sally?

Our AI-powered scanner gives you a deeper, real-time smart contract analysis — free, with every scoring factor shown.

Get Detailed Audit