EVM patterns
ERC20 Token Audit: The Listing Packet and Free Self-Checks
Before listing, an issuer needs evidence for token behavior and the integrations that rely on it. An ERC20 token audit ties that evidence to a revision, current authority and the remaining compatibility limits.

Key facts
- Fixture sample
- 20 variants after excluding 2 support files
- Approval surface
- 12 of 20 declare approve directly
- Transfer declarations
- 9 of 20 declare transfer directly
- Review boundary
- Fixtures were inspected, not executed
Mint authority before a listing
An ERC20 token audit checks whether a token's behavior and administrative controls match the specification that exchanges and other integrations will rely on. Conformance to an interface is only part of that job. An exchange also needs to know whether supply can change, transfers can be restricted or the implementation can be replaced after onboarding.
Begin with a release manifest.
Bind the repository revision to the deployed address and chain, identify any proxy and name the intended integrations. A review of an earlier token version is useful background but cannot establish that the candidate for listing behaves the same way. Preserve compiler settings and dependencies so another reviewer can reproduce the build.
For mint authority, trace every reachable issuance path and the party permitted to use it.
A fixed initial supply differs from an ongoing minter role, and a capped role differs from an administrator able to raise the cap. If a bridge issues representations on another chain, the issuer's supply statement must explain which supply it describes.
- Initial issuance
- The deployment operation that creates balances and the recipients it names.
- Ongoing issuance
- Entry points available after deployment and their authorization checks.
- Supply constraint
- The enforced limit and every action that can change it.
- Deployment evidence
- The candidate address, implementation and configuration used for the review.
Do not equate a helper named _mint with a public mint permission.
Reachability decides the capability. The OpenZeppelin ERC20 reference describes extensions that applications compose. The review must inspect the resulting application rather than assuming the extension name defines its complete behavior.
Publish the remaining issuance authority in the listing packet.
An integration can account for a disclosed capability more reliably than a claim of fixed supply contradicted by a role holder. The broader smart contract backdoors guide covers the authority graph behind these controls.
Our fixture census: transfer-only checks miss part of the surface
We counted explicit entry-point declarations in every eligible source fixture of the weird ERC20 repository.
Of 20 variants, 12 declare approve and 6 declare neither transfer nor transferFrom locally. Those 6 still belong in a compatibility review. Inherited transfer code does not make approval or metadata differences disappear.
Method
- Source
- d-xo/weird-erc20 at the measured revision
- Retrieved
- Population and selection
- All immediate src/*.sol source files, excluding ERC20.sol base and test.t.sol harness. Counts explicit transfer, transferFrom and approve declarations after stripping comments. Inherited implementations are not counted. Fixtures are not deployed tokens.
- All repository files
- 33
- Source files
- 22
- Base and harness
- 2
- Included variants
- 20
- Revision
781c8f039c106eb2d5c6071046b0dbb2f72c9870
Results
| Observation | Count | Denominator |
|---|---|---|
| Eligible variant source files | 20 | 22 immediate Solidity source files |
| Direct transfer declarations | 9 | 20 variants |
| Delegated transfer declarations | 14 | 20 variants |
| Approval declarations | 12 | 20 variants |
| Files declaring neither transfer entry point | 6 | 20 variants |
Limits
- We excluded the base ERC20.sol and the test.t.sol harness. The remaining 20 files are example variants, not a random sample of assets.
- Counts describe explicit source declarations after comment removal. Inherited functions remain available where defined by a base contract.
- We did not execute the fixtures or the conformance checker, and we did not classify vulnerabilities. A declaration count is a guide to review coverage.
- The repository contains teaching examples based on unusual behavior. Its proportions cannot estimate the prevalence of that behavior among listed tokens.
The reproducible script is seo/research/erc20-variant-survey.py. The fixed evidence is seo/research/erc20-variant-survey-2026-09-05.json.
Both are kept in the repository and are not published as downloads. The output retains request statuses and raw evidence so a later review can distinguish a source change from a counting error.
Blacklist and pause behavior
A listing review should establish which addresses and operations can be restricted. Transfers from an ordinary wallet may work while a deposit route fails because its recipient or operator has different treatment. Test the actual integration roles on an isolated fork, then distinguish what was observed at that block from what an administrator may configure later.
| Path | Condition to vary | Evidence to keep |
|---|---|---|
| Direct transfer | Sender and recipient restrictions | Return behavior and balance changes |
| Delegated transfer | Operator identity and allowance | Spender path and allowance effect |
| Deposit | Custody address treatment | Amount credited against amount received |
| Withdrawal | Pause and recipient conditions | Failure handling without false completion |
Ask who can pause and who can unpause. These may be different roles. A token with no pause path cannot provide emergency stopping merely because an incident plan says it will. A token with a pause path creates a dependency on whoever controls recovery. Make the operational consequence explicit.
A blacklist capability can be intentional. The review finding should identify an undocumented restriction, an authorization defect or an integration assumption it breaks. An issuer and exchange can then decide whether the documented behavior is acceptable. A scanner's boolean flag cannot make that commercial decision on their behalf.
If the intended deposit adapter is not built yet, state that integration testing remains outstanding. Token unit tests cannot stand in for a nonexistent adapter. Keep the token review and the listing integration review as separately identifiable deliverables.
Fee-on-transfer and amount accounting
A transfer request specifies an amount, but an integration must establish how that request affects balances. A fee can leave the recipient with less than the requested quantity. Rebasing or other balance changes can create different accounting assumptions again. These cases are not interchangeable, and a return value alone does not tell an exchange how much to credit.
The weird ERC20 repository provides small examples of surprising behavior, including a transfer fee and missing return values. The examples are useful fixtures for an integration test suite. They are not a deployment inventory and do not show which behavior a specific asset currently uses.
- Capture the recipient balance before an isolated deposit action.
- Execute through the intended adapter using a controlled test account. Observe success or failure and the data returned.
- Compare the resulting balance change with the credit the adapter records. Explain any difference from the requested quantity.
- Repeat with the token's documented fee and restriction states. If future fee changes are permitted, test the supported range or explicitly reject unsupported states.
A safe transfer wrapper helps normalize certain return conventions. It does not guarantee that a token is fee-free, that its balance is stable or that an upgrade will preserve behavior. The wrapper's documented guarantees and the exchange's accounting assumptions should be written as separate statements.
For the issuer, the cheapest compatibility improvement may be removing an unnecessary custom transfer behavior before the review. If it is essential to the product, document it as a requirement and provide an integration fixture. Do not hide it behind a generic ERC20 compliant statement.
- Requested amount
- The user or adapter requests a transfer quantity.
- Token execution
- Token logic applies its documented rules to the call.
- Received balance
- The recipient balance change records the effect of those rules.
- Credited amount
- The integration must justify its credit against the actual received amount.
Permit and EIP-2612
EIP-2612 adds signed approvals through permit, with a nonce and a domain separator. It authorizes an allowance change. It does not itself transfer tokens. Listing teams should identify the actual permit variant and the wallet flows expected to use it, because similar names do not establish identical semantics.
A valid signature is bound to the specified message and domain. Review the owner, spender and value alongside the deadline and nonce. Replay protection depends on these checks behaving correctly for the deployment being used. A chain or contract mismatch should not be silently repaired by a user interface that asks the user to sign a different message.
| Element | Review question | Useful test |
|---|---|---|
| Domain | Does the signature apply to this deployment? | Reject a signature for another domain |
| Nonce | Can a consumed authorization be used again? | Attempt the same signed authorization again locally |
| Deadline | Is expired authority rejected? | Advance the test environment beyond expiry |
| Spender and value | Does the resulting allowance match authorization? | Compare the signed fields with stored allowance |
The standard discusses a relayer's option to withhold a permit. Design the product flow so a user can understand a signature that was created but never submitted. It also describes the risk of an unchanging domain separator across a future chain split. These are specification boundaries worth reviewing, not evidence that every implementation is affected in the same way.
Do not require permit solely to make a listing packet look modern. If the integration does not use it, say so. If it does, include the signature path in scope and check the supported wallet types. Our signature replay analysis provides the wider context for domain binding and authorization reuse.
Ownership and timelock evidence
An exchange needs the effective administrator, not just the value returned by owner(). Role-based contracts can have several administrators, and an upgradeable token can have authority outside the token implementation. Follow the path from each sensitive action to the accounts or governance contracts able to authorize it.
The OpenZeppelin access control guide separates simple ownership from roles and delayed administration. Apply those distinctions to the candidate deployment. A multisignature wallet can reduce reliance on an individual key, while a timelock changes scheduling. Neither automatically removes the ability to change token behavior.
- Current control
- The account or contract able to act under the reviewed configuration.
- Administrative control
- The authority that can replace that account or grant equivalent permissions.
- Delayed execution
- The actions that require scheduling and the mechanisms that can cancel or bypass it.
- Change notification
- The observable events and communication channel an integration will monitor.
Key custody is part of the evidence packet even when private key material is never shared. Describe the signing arrangement and operational responsibilities. An auditor should not need a production secret to assess the design. A local reproduction should use test keys and preserve the same authorization structure where relevant.
If ownership is renounced before the listing, record which functionality becomes unavailable and which other authorities remain. Irreversible removal can break recovery or maintenance assumptions. Review that transition before performing it. A final ownership state is not enough to explain whether the intended operating model still works.
Free self-checks before requesting a quote
Slither's ERC conformance utility checks interfaces and related structure, including function presence, return types and event details. Run it against the candidate source and save its output with the revision. A successful run narrows a conformance question. It does not certify every economic or administrative property of the token.
slither-check-erc contract.sol ContractName- Reproduce the build from a clean environment. Pin dependencies and compiler settings and explain any generated source.
- Compare verified source with the candidate implementation and deployment configuration. For a proxy, identify the implementation actually in use.
- Run conformance checks and preserve both warnings and errors. Resolve failed tool setup before interpreting the output.
- Run unit and integration tests for allowance, balances and failure handling. Include the token's intentional deviations.
- Document role holders and key custody without exporting secrets. Assign an owner to each unresolved review question.
The token integration checklist combines automated checks with manual questions. Some guidance reflects older compiler conventions, so apply it against the actual compiler and dependency versions rather than copying every line mechanically. For example, a historical checklist mentioning SafeMath is not by itself a reason to add that library to modern checked arithmetic.
A failed checker installation is not a failed token, and a checker that could not resolve source has not passed the contract. Store the tool version, exact command and exit outcome so a reviewer can distinguish setup problems from findings. The tools catalog helps locate supporting utilities. The final packet should still contain the evidence those tools produced.
Before commissioning work, have someone outside the implementation team follow the reproduction instructions. Their difficulty finding the correct revision or understanding a test is useful feedback. Fixing the packet early gives the paid reviewer more time to investigate behavior.
Where a paid review starts
A paid token review should begin with the questions your free checks cannot answer confidently: whether the authority graph matches the promises, whether the intended integrations handle unusual states and whether implementation changes invalidate earlier assumptions. Provide the unresolved questions with the source package. Avoid paying for a report that merely repeats a scanner's labels without examining their consequences.
There is no defensible universal token contract audit cost from interface size alone. Custom transfer logic, cross-contract dependencies and remediation expectations change the work. Ask for quotes against the same revision and deliverables, using the audit scope builder. The Halborn company analysis is one directory reference for comparing providers' scope.
- Finding
- A reproducible behavior linked to a violated requirement or an explicitly accepted risk.
- Fix review
- Assessment of the proposed change against the finding and any new behavior it introduces.
- Release evidence
- The final revision and configuration to which the conclusions apply.
- Residual risk
- Authority or integration constraints that remain after the reviewed changes.
Freeze the release packet when the review ends. If a fee setter or proxy implementation changes afterward, ask whether the changed behavior remains covered. A listing is an operational decision about a particular asset and integration, while an audit is evidence with a defined boundary. Keeping that boundary visible makes both decisions easier to revisit.
Request an acceptance matrix for the actual listing integration. Each row should identify a supported behavior, the evidence produced and the owner of an unresolved decision. This lets an exchange reject an unsupported fee model without suggesting that the entire token is malicious, and it lets an issuer distinguish an integration limitation from a contract defect.
Include a final deployment readback after configuration. A reviewed source tree can still be deployed with an unexpected administrator or initialization argument. Preserve the observed implementation and role configuration with the report, then explain any differences from the reviewed candidate. Treat an unexplained difference as an open release question rather than editing the source manifest to hide it.
For distribution and issuance assumptions, cross-check the tokenomics review. A listing packet should not say fixed supply in its commercial summary while the technical appendix describes a live minter role. Resolve that inconsistency in the public description or the implementation and ask the reviewer which evidence now supports the claim.
Frequently asked questions
Must an exchange accept a token because it passes ERC conformance checks?
No. Acceptance also depends on the exchange's custody and integration requirements. Supply controls or intentional transfer behavior may be incompatible with that integration even when interface checks pass.
Should a token change its decimals just to match an exchange example?
Confirm the integration requirement first. Changing display precision can alter assumptions in user interfaces and calculations. Preserve the intended units and test the complete integration rather than copying a sample value.
Can I reuse the packet for a wrapped version on another chain?
Only the shared background carries over automatically. Identify the wrapper or bridge logic, deployment authority and chain-specific configuration as a new scope. State which earlier findings remain applicable and which require review.