WATS Wallet Info

WATS Wallet is a self-custody, multi-chain Web3 wallet built by Alltoscan LLC and shipped as three products under one brand: a Chrome extension, a mobile app and an NFC Metal Card. It covers Ethereum, Arbitrum, Optimism, Base, Polygon, BNB Chain, Solana and TON. On EVM networks every action is charged in one token, ATS, through an ERC-4337 paymaster that debits a single balance on BSC; Solana transactions pay their own native fee in SOL, while fees on TON are paid in ATS too. WATS does not natively support Bitcoin, and it never holds your keys.

WATS Wallet 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.

72.02
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
0xf0A8...8cd4
Network
BNB Smart Chain - Mainnet
License MIT
Compiler v0.8.28+commit.7893614a
Type Paymaster
Language Solidity
Onboard date 2026/10/17
Revision date 2026/10/22

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.

Ownership is not renounced

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

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 ATSPaymaster v2 contract is a revision of the previously audited ERC-4337 v0.8 token paymaster that lets users pay their gas in ATS instead of the native coin of the chain. Every operation now carries a 29-byte header in its paymaster data that the account owner signs: a mode byte, a maximum ATS charge (maxAts) and a validity window. Three modes exist. The user mode takes the worst-case fee from the sender's allowance during validation and refunds the excess after execution, at the larger of a minimum charge of roughly one dollar and the gas cost plus a markup. Two backend-signed modes run at cost price without the minimum charge: a prepaid setup mode that also takes the fee during validation, and a bootstrap mode for the very first operation that only checks the sender's balance during validation and takes the fee after execution, because the approval is only granted inside that operation. The re-audit covered the source verified on Sourcify with an exact match on BSC testnet, Arbitrum Sepolia, Base Sepolia and Polygon Amoy; all four deployments share one source tree, and the compiler settings and library versions are unchanged from the first audit.

Ownership Privileges

The ownership is held through a two-step handover. On the four v2 testnet deployments the owner is still the deploying EOA and no transfer is pending; for mainnet the team intends the same 2-of-3 Safe that owns the legacy contracts. The owner retains the following privileges:

  • Setting the exchange-rate band, the maximum rate age (60 seconds to 1 day), the markup (at most 200%), the per-operation gas cap and the cap on the minimum charge; the last two have no hard limit in code
  • Appointing and removing rate updaters and the backend signer, changing the rate-drift cap, the bootstrap markup (at most 100%) and the post-operation gas allowance (at most 100,000 gas), and pausing sponsorship
  • Withdrawing the EntryPoint deposit and any stake, and sweeping collected ATS to any address; the sweep emits an event and always leaves one unit in the contract
  • The owner cannot renounce ownership, cannot move ATS out of user wallets outside an operation the user signed, and cannot raise the price of an operation already in flight above the ceiling the user signed
  • The rate updater can only set rates inside the owner's band, minimum charges below the owner's cap and, when a drift cap is set, move the rate by at most that cap per call and per one-hour window
  • No owner action takes effect with a delay, as no timelock is in place

Security Features

The contract implements several positive security features:

  • The declared post-operation gas limit is bounded to 40,000 to 300,000 gas and the EntryPoint's unused-gas penalty for that limit is priced into every fee, so a self-bundling user can no longer drain the deposit
  • A user-signed maximum charge is enforced before any ATS moves, and all fee inputs are captured at validation, so later configuration changes or front-running cannot raise the amount a user pays
  • The user mode and the prepaid setup mode collect the full worst-case fee during validation, which reliably prevents users from escaping payment by revoking their allowance during execution
  • Backend signatures are bound to a version tag, the sender, nonce, call data, all gas fields, the signed header, the chain id and the paymaster address, and invalid signatures return a failed-signature result instead of reverting
  • The rate updater is confined by a band, a per-call and per-hour drift cap, and range-checked freshness; setBounds resets an out-of-band rate and clamps the minimum charge
  • Configuration is packed into six storage slots, all reverts use custom errors, the pragma is pinned to 0.8.28 and ownership cannot be renounced

Re-audit Outcome

All prior findings were re-tested against the real EntryPoint v0.8 runtime. The high-severity deposit drain through the unused post-operation gas penalty is fixed: out-of-range limits are rejected, and fuzzed operations at cost price never left the deposit under-compensated. The missing user maximum charge, the single-call rate jump limit, the out-of-band rate after setBounds, the reverting signature checks, the unchecked maximum rate age, the missing sweep event, the documentation and the renounce, custom-error and storage-packing items are all fixed. The bootstrap concern is only partially fixed: the new prepaid setup mode takes its fee during validation, but the true first-operation bootstrap mode still collects after execution and can still be made to pay nothing by a same-bundle balance move or a delegate that ignores the approval. The team documents this as a known residual bounded per operation by the gas cap and in number only by the backend's signing policy. The governance item is partially addressed: the unused rate updater was revoked on all ten legacy chains, but there is no timelock, the deployer EOA remains a Safe signer, and the testnet contracts are owned by that EOA and unstaked. No new vulnerability was introduced by the changes. Two properties are worth noting: the fixed one-hour drift windows allow two full caps back to back across a window boundary, and the validity window of a backend-signed operation is not capped on-chain. Slither and Aderyn reported no new valid issue.

Note - This re-audit report consists of a security analysis of the ATSPaymaster v2 smart contract. This analysis did not include economic analysis of the contract's tokenomics. Moreover, we only audited the main contract for the ATSPaymaster team. Other contracts associated with the project were not audited by our team. The legacy paymasters remain deployed on mainnet until the v2 contracts replace them. We recommend investors do their own research before investing.

Files and details

Findings and Audit result

high Issues | 1 findings

Resolved

#1 high Issue
Unpriced postOp unused-gas penalty allows a permissionless deposit drain
ATSPaymaster.sol
L161-165
L313-369
L406
Description

After postOp returns, the EntryPoint charges the paymaster an extra ten percent of any unused paymasterPostOpGasLimit. The contract tries to cover this tail with the fixed postOpTailGas value of 45,000 gas, but on the normal path the user chooses the postOp gas limit freely and the contract never reads or bounds it. Because the cost passed into postOp is calculated before this penalty is added, the fee formula never sees it. A user who submits their own bundle can set a very large postOp limit, pay only the ATS floor of roughly one dollar and receive the penalty as the bundle beneficiary out of the paymaster deposit. With the live BSC configuration one such operation cost the deposit 0.00214 BNB while collecting ATS worth only 0.00139 BNB, and the attacker kept the difference. No backend signature is needed and the operation can be repeated until the deposit is empty.

medium Issues | 2 findings

Acknowledged

#1 medium Issue
Bootstrap path collects only in postOp and can be made to pay nothing
ATSPaymaster.sol
L275-297
L350-351
L415
Description

On the backend signed bootstrap path the contract only checks during validation that the sender holds enough ATS and takes the fee later in postOp. Anything that empties that balance or skips the approval between the two steps makes postOp revert. The EntryPoint then rolls back the execution but still charges the paymaster deposit and pays the bundler, while no ATS is collected. An attacker can place an earlier operation of the same sender in the same bundle that moves the ATS away, or delegate the account to a contract whose execute function ignores the approval, because the signed hash covers the raw initCode and not the delegate the account actually runs. The same small ATS balance can be recycled across fresh accounts. The contract's own comments name this drain pattern as the reason the normal path pre-charges, yet the bootstrap path keeps it open and relies only on off-chain rate limits.

Resolved

#2 medium Issue
Fee parameters are uncapped and users have no maximum charge
ATSPaymaster.sol
L126-142
L193-208
L331-333
Description

markupBps is set through setBounds without any upper limit, and minChargeAts can be moved anywhere up to minChargeCap by the rate updater, while minChargeCap itself is also unbounded. On the normal path the user approves the paymaster, usually for an unlimited amount, and signs an operation that carries no ceiling on the ATS it is prepared to pay. The charge is computed from whatever parameters are live when the bundle is included. In our testing a single rate updater transaction placed before inclusion raised the charge of an already signed operation from about 23.5 ATS to the 80 ATS cap, and an owner markup of 1,000,000 basis points produced a charge of more than 266 ATS for a small operation. Fees above 25 percent can therefore be applied at any time. If the updater and owner were fully trusted policy actors this would be closer to a low risk, but the contract's own comments treat a captured rate updater as a threat that the band and jump limit must contain, so the exposure sits inside the threats the project itself designed against.

low Issues | 4 findings

Resolved

#1 low Issue
Rate jump limit only restricts single calls
ATSPaymaster.sol
L193-208
Description

maxRateJumpBps limits how far a single setRate call can move the rate, and the code comments state that an attacker would therefore have to sustain a manipulation over many keeper intervals. There is no time component in the check, so the updater can simply call setRate several times in the same block. In our testing 18 consecutive calls moved the BSC rate from its live value to the lower band edge within one block, which reduced the ATS quoted for 0.01 BNB of gas from about 186.7 ATS to 29.5 ATS. A compromised or faulty updater key can reach either band edge immediately.

Resolved

#2 low Issue
setBounds leaves an out-of-band rate in force
ATSPaymaster.sol
L126-142
Description

setBounds writes the new band and caps without checking the live rate and minChargeAts against them. When the band is moved away from the current rate, the old rate keeps pricing every operation even though it now lies outside the owner's band, and minChargeAts can remain above the new cap. While the jump limit is active the updater cannot reach any value inside the new band, because each jump is measured from the stale rate, so operations stay mispriced until the owner changes the jump setting again.

Resolved

#3 low Issue
Invalid backend signatures revert instead of failing gracefully
ATSPaymaster.sol
L300-306
L374-383
Description

The comments say that an invalid backend signature returns a failed signature result instead of reverting. The ECDSA recover function used here reverts for zeroed, malformed, high-s and non 65 byte signatures, and paymasterData shorter than 12 bytes reverts while being sliced. Such operations abort validation with a revert, which breaks gas estimation with dummy signatures and departs from the ERC-4337 rule that signature problems must return SIG_VALIDATION_FAILED. The bootstrap path also accepts a validUntil of zero, so an authorisation never expires and is bounded only by rate freshness, while the remote paymaster explicitly forbids this.

Resolved

#4 low Issue
maxRateAge is not range-checked
ATSPaymaster.sol
L126-142
L214-222
Description

setBounds accepts any value for maxRateAge. A value of zero makes the validity window end at the moment of the last rate update, so operations only validate in the keeper's own block; in our testing every operation one second later failed with AA32 and every quote reverted with stale rate, which amounts to a full sponsorship outage. A value close to the uint256 maximum makes rateValidUntil overflow, so every validation reverts while rateFresh and the quotes still report a healthy rate. Very large finite values keep operations valid at an old rate long after the keeper has stopped, three years in our test. All three are owner-only mistakes that the owner can undo, but the contract does nothing to prevent them.

optimization Issues | 2 findings

Resolved

#1 optimization Issue
Use custom errors instead of revert strings
ATSPaymaster.sol
L134-202
L318-350
Description

All checks use require with revert strings. Custom errors are cheaper to deploy and to revert with, and they make failures easier to decode for off-chain tooling.

Resolved

#2 optimization Issue
Pack configuration into fewer storage slots
ATSPaymaster.sol
L60-102
Description

Every configuration value occupies its own 32 byte slot, so validation reads around nine cold storage slots for paused, rate, maxGasCostWei, postOpTailGas, the markup, the floor, rateUpdatedAt, maxRateAge and backendSigner. Values such as basis points, tail gas, the maximum age and the update timestamp fit easily into smaller types.

informational Issues | 4 findings

Acknowledged

#1 informational Issue
Governance and key management: no timelock, hot operational keys, unstaked paymasters
ATSPaymaster.sol
L126-189
Description

This is a disclosure of the operational trust assumptions rather than a code defect. The owner is a 2 of 3 Safe that can change every fee and limit, the backend signer, the rate updaters and the pause flag, withdraw the EntryPoint deposit and sweep all collected ATS to any address, all with immediate effect. One of the three Safe signers is the deployer EOA, which is also used for routine transactions. Two rate updater EOAs are authorised on all ten chains although only one of them is still used, and a single backend signer EOA is shared by both paymasters on every chain. None of the paymasters is staked in the EntryPoint, although the comments assume a staked paymaster for ERC-7562 compliance, so public ERC-7562 bundlers will not serve them.

Resolved

#2 informational Issue
sweepAts does not emit an event
ATSPaymaster.sol
L182-184
Description

sweepAts moves collected ATS to any address without emitting an event of its own. The token Transfer event still records the movement, but monitoring that relies on the paymaster's events will not see sweeps. On BSC 18,000 ATS were swept to an unverified contract in this way.

Resolved

#3 informational Issue
Documentation is Turkish only and partly inconsistent with the code
ATSPaymaster.sol
L14-44
L82-88
Description

All NatSpec is written in Turkish, which limits review by external integrators. The contract header states that both sponsorship paths charge at least one dollar, while the bootstrap path applies no floor and uses its own markup, and the inline claim that invalid signatures never revert does not hold.

Resolved

#4 informational Issue
Ownership can be renounced, which would lock the deposit
ATSPaymaster.sol
L45
Description

The inherited renounceOwnership function is still available. If it were called, the EntryPoint deposit, any stake and all collected ATS could never be withdrawn, because withdrawTo, withdrawStake and sweepAts are owner only.