{"id":20640516,"url":"https://github.com/kovart/forta-token-impersonation-agent","last_synced_at":"2025-07-21T03:02:54.229Z","repository":{"id":97652074,"uuid":"496296088","full_name":"kovart/forta-token-impersonation-agent","owner":"kovart","description":"The bot detects token impersonation","archived":false,"fork":false,"pushed_at":"2023-08-09T16:11:53.000Z","size":77241,"stargazers_count":6,"open_issues_count":3,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-15T23:02:31.325Z","etag":null,"topics":["bot","erc1155","erc20","erc721","ethereum","forta","impersonation","token"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kovart.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-05-25T15:48:36.000Z","updated_at":"2023-04-08T10:07:44.000Z","dependencies_parsed_at":"2024-11-16T15:41:21.281Z","dependency_job_id":null,"html_url":"https://github.com/kovart/forta-token-impersonation-agent","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/kovart/forta-token-impersonation-agent","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kovart%2Fforta-token-impersonation-agent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kovart%2Fforta-token-impersonation-agent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kovart%2Fforta-token-impersonation-agent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kovart%2Fforta-token-impersonation-agent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kovart","download_url":"https://codeload.github.com/kovart/forta-token-impersonation-agent/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kovart%2Fforta-token-impersonation-agent/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266231762,"owners_count":23896473,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bot","erc1155","erc20","erc721","ethereum","forta","impersonation","token"],"created_at":"2024-11-16T15:29:46.092Z","updated_at":"2025-07-21T03:02:54.200Z","avatar_url":"https://github.com/kovart.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Token Impersonation Bot\n\n## Description\n\nThis bot detects creation of an impersonating token.\nFor example, the bot will detect when an attacker creates a copy of an existing APE token (ApeCoin),\nwhich will be used for subsequent scams.\nThe key to determining whether a token is an impersonator is the token symbol, name and its interface.\nTokens deployed from the same address are ignored.\n\n## Supported Token Interfaces\n\n- ERC20\n- ERC721\n- ERC1155\n\n## Supported Chains\n\n- Ethereum (1)\n- BSC (56)\n- Polygon (137)\n- Arbitrum (42161)\n- Optimism (10)\n- Fantom (250)\n- Avalanche (43114)\n\n## Configuration\n\nSome protocols can create tokens with the same name.\nTo reduce the noise caused by such tokens, you can specify a name and a symbol that will be ignored.\nYou can either combine them, increasing the accuracy of the check, or specify either symbol or name.\n\nBy default, the bot ignores the deployment of Uniswap tokens:\n\n```json\n{\n  \"exclude\": [\n    {\n      \"symbol\": \"UNI-V2\"\n    }\n  ]\n}\n```\n\n## Alerts\n\n- IMPERSONATED-TOKEN-DEPLOYMENT\n\n  - Fired when someone deployed an impersonating token\n  - Severity is always \"medium\"\n  - Type is always set to \"suspicious\"\n  - Metadata:\n    - `newTokenSymbol`: symbol of the deployed token\n    - `newTokenName`: name of the deployed token\n    - `oldTokenSymbol`: symbol of the original token\n    - `oldTokenName`: name of the original token\n    - `newTokenDeployer`: address that deployed a contract that impersonates another token\n    - `newTokenContract`: address of the contract that impersonates another token\n    - `oldTokenDeployer`: address that deployed the original token\n    - `oldTokenContract`: address of the original token contract\n\n- IMPERSONATED-TOKEN-DEPLOYMENT-POPULAR\n  - Fired when someone deployed a contract that impersonates a popular token\n  - Severity is always \"high\"\n  - Type is always set to \"suspicious\"\n  - Metadata:\n    - `newTokenSymbol`: symbol of the deployed token\n    - `newTokenName`: name of the deployed token\n    - `oldTokenSymbol`: symbol of the original token\n    - `oldTokenName`: name of the original token\n    - `newTokenDeployer`: address that deployed a contract that impersonates another token\n    - `newTokenContract`: address of the contract that impersonates another token\n    - `oldTokenDeployer`: address that deployed the original token\n    - `oldTokenContract`: address of the original token contract\n\n## Test Data\n\n#### Ethereum Mainnet (Chain 1)\n\nAlert `IMPERSONATED-TOKEN-DEPLOYMENT` for \"GOLIATH (Goliath)\" token:\n\n```bash\n$ npm run tx 0xd9eef1565c3e580a207855aa76baab84033c79f1accf449b1d3848d5e9c795a9\n```\n\n## Token Data\n\nThe bot uses tokens collected at runtime as well as pre-generated tokens.\nToken data is located in the [data](./data) folder. Each chain uses its own file.\nFor example, for the `Mainnet`, the file will be called `chain-1.csv`, since 1 is the id of that network.\n\n## Data Generation\n\nPre-generated token data can be collected in two ways.\n\n### Automatic\n\nAll you need to do is run the following command, passing an id of the desired network:\n\n```bash\n$ npm run fetch:auto 137\n```\n\nFor instance, this command starts scanning blocks of the last 28 days on the Polygon network.\nThe script searches for tokens by their traces in transaction events.\nIf a discovered token has a similar hash to a previously discovered one, the script finds the most popular one.\nIf the new token is more popular, it will be written to the end of the data file,\nso that it will overwrite the previous one.\nIf the previous token is more popular, the new token will be ignored.\n\nAll tokens found will be written to the `chain-137.csv` file. Also, a state file `chain-137.fetcher.json` will be created,\nwhich will contain the scanned range of blocks, and which can be used by the script for optimizations in subsequent runs.\n\n## List\n\nThe most accurate way to generate data is to use prepared list of token addresses.\nIt can be obtained from services such as [dune.com](https://dune.com).\n\nFor example, this query allows you to get the most popular erc20 tokens for 3 months:\n\n```sql\nSELECT contract_address, events\nFROM (\n    SELECT\n        COALESCE(transfer_table.contract_address, approval_table.contract_address) as contract_address,\n        COALESCE(transfer_count, 0) + COALESCE(approval_count, 0) as events\n    FROM (\n        SELECT contract_address, COUNT(DISTINCT \"spender\") as approval_count\n        FROM erc20.\"ERC20_evt_Approval\"\n        WHERE evt_block_time \u003e= now() - interval '3' month\n        GROUP BY contract_address\n    ) as approval_table\n    FULL OUTER JOIN (\n        SELECT contract_address, COUNT(DISTINCT \"to\") as transfer_count\n        FROM erc20.\"ERC20_evt_Transfer\"\n        WHERE evt_block_time \u003e= now() - interval '3' month\n        GROUP BY contract_address\n    ) as transfer_table\n    ON (transfer_table.contract_address = approval_table.contract_address)\n) as events_table\nWHERE events \u003e= 50\nORDER BY events DESC\n```\n\nThe list of token addresses must be placed in the [data](./data) folder, named chain-{ID}.list.erc{INTERFACE}.csv.\nWhere {ID} is a chain id of the tokens and {INTERFACE} is the tokens standard (20, 721, 1155).\n\nThen you have to run the following command, which will do everything automatically:\n\n```bash\n$ npm run fetch:list {ID}\n```\n\n---\n\n\u003e Beware, if you change hash function, you should re-generate token data\n\n---\n\nYou can also specify a custom RPC server for each network separately.\nBy default, the project stores the network configurations in the [networks.config.json](./networks.config.json) file.\n\nYou can find suitable open RPC servers on [https://chainlist.org](https://chainlist.org).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkovart%2Fforta-token-impersonation-agent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkovart%2Fforta-token-impersonation-agent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkovart%2Fforta-token-impersonation-agent/lists"}