{"id":19733067,"url":"https://github.com/bhemen/usdt","last_synced_at":"2025-08-01T16:40:06.419Z","repository":{"id":180464943,"uuid":"568115730","full_name":"bhemen/usdt","owner":"bhemen","description":"Tools for scraping data about Tether's USDT from Ethereum","archived":false,"fork":false,"pushed_at":"2023-11-14T20:10:44.000Z","size":168,"stargazers_count":8,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-08T07:43:19.213Z","etag":null,"topics":["blockchain","python","stablecoin","tether","usdt"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bhemen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2022-11-19T13:57:54.000Z","updated_at":"2025-01-21T12:57:45.000Z","dependencies_parsed_at":null,"dependency_job_id":"a309ee69-3f77-4d39-8921-040bba9c167c","html_url":"https://github.com/bhemen/usdt","commit_stats":null,"previous_names":["bhemen/usdt"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhemen%2Fusdt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhemen%2Fusdt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhemen%2Fusdt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhemen%2Fusdt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bhemen","download_url":"https://codeload.github.com/bhemen/usdt/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253025333,"owners_count":21842409,"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":["blockchain","python","stablecoin","tether","usdt"],"created_at":"2024-11-12T00:29:03.136Z","updated_at":"2025-05-08T07:43:24.812Z","avatar_url":"https://github.com/bhemen.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Python scripts for analyzing USDT on Ethereum\n\n## USDT\n\nUSDT is a fiat-backed stablecoin issued by Tether.  You can read about the off-chain reserves backing USDT at Tether's [transparency](https://tether.to/en/transparency/) page.\nTether currently issues USDT on [14 blockchains](https://tether.to/en/transparency/), but this repository focuses on the contracts that control USDT on Ethereum.\nOn Ethereum, USDT is implemented as an ERC-20 contract, but it has significant additional functionality beyond the minimum specified by the [ERC-20 standard](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/).\n\nThis repository is provided to aid in analysis of the on-chain use of USDT.  If you are considering *using* USDT, please read the [terms of service](https://tether.to/en/legal/).\nAlthough it's not stated explicitly in the Terms of Service, Tether also says you [cannot withdraw in amounts under 100,000](https://tether.to/es/fees/).\n\n## Contract overview\n\nThe USDT contract is deployed at [0xdAC17F958D2ee523a2206206994597C13D831ec7](https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7).\n\nFollowing [OpenZeppelin standards](https://docs.openzeppelin.com/contracts/2.x/api/ownership#Ownable), the USDT contract is \"ownable\", \nand the owner is [0xC6CDE7C39eB2f0F0095F41570af89eFC2C1Ea828](https://etherscan.io/address/0xC6CDE7C39eB2f0F0095F41570af89eFC2C1Ea828).\nThe owner is [Gnosis Safe](https://gnosis-safe.io/).  This multisig wallet is a 3-out-of-6 multisig, controlled by the following 6 Externally Owned Accounts\n\n* [0xf4B51B14b9EE30dc37EC970B50a486F37686E2a8](https://etherscan.io/address/0xf4B51B14b9EE30dc37EC970B50a486F37686E2a8)\n* [0xEe5207d3c88562fc814496Af0845B34CFD4afc8c](https://etherscan.io/address/0xEe5207d3c88562fc814496Af0845B34CFD4afc8c)\n* [0x61D5a4d5Bd270e59E9320243e574288e2a199fED](https://etherscan.io/address/0x61D5a4d5Bd270e59E9320243e574288e2a199fED)\n* [0x25bB61643e4881147E6aabb65e6DD45CF2904155](https://etherscan.io/address/0x25bB61643e4881147E6aabb65e6DD45CF2904155)\n* [0x4096a34E582664F969753b34dA6E72D55b3C85C1](https://etherscan.io/address/0x4096a34E582664F969753b34dA6E72D55b3C85C1)\n* [0x4D915Dd2c56814BD3Db51a1dA35b302BCC9c8973](https://etherscan.io/address/0x4D915Dd2c56814BD3Db51a1dA35b302BCC9c8973)\n\nThe contract is also \"[Pausable](https://docs.openzeppelin.com/contracts/4.x/api/security#Pausable)\", meaning that the owner can pause the contract at will.  In the context of \nUSDT, pausing the contract prevents all transfers (including mints and burns).\n\nThe contract is \"[Blacklistable](https://github.com/centrehq/centre-tokens/blob/master/contracts/v1/Blacklistable.sol)\", meaning that special accounts (\"Blacklisters\") can selectively \nfreeze the funds of target users.  Basically, the contract will not process transfers from \"Blacklisted\" addresses ([See Line 340](https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7#code)).\nIt appears that Tether allows you to transfer USDT *to* \"blacklisted\" addresses.  This diverges from Circle's functionality.\n\nSince mints and burns are special types of transfers, you cannot mint funds to or burn funds from a \"blacklisted\" address.\nUnlike the \"Ownable\" and \"Pausable\" which were standardized by OpenZeppelin and used by a wide variety of contracts, the Blacklistable property was developed by Centre and the code seems to be specific to the USDT \ncontract.  Other fiat-backed stablecoins (e.g. USDC, USDP, BUSD) implement a similar functionality, but with different terminology and code.\n\nThe USDT contract charges a fee on every transfer ([See Line 184](https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7#code#L184)), [currently that fee is set to 0](https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7#readContract#F17), \nso effectively there is no fee, but the existence of code supporting a transfer fee indicates an interest in assessing a transfer fee.\n\n## Tools\n\n[get_usdt_configs.py](get_usdt_configs.py) Will scrape all \"configuration\" events from the USDT contract.  Specifically, it scans the Ethereum blockchain for the following events, \nand records them to [data/usdt_configs.csv](data/usdt_configs.csv).\n\nThe events emitted by the USDT contract (e.g. AddedBlacklist, Issue etc) do *not* record the caller's address.  So we have to get that separately.\nThe script [add_sender.py](add_sender.py) adds a new column (\"msg.sender\") to [data/usdt_configs.csv](data/usdt_configs.csv).\n\nThe file [analysis/usdt_analysis.py](analysis/usdt_analysis.py) does some basic analytics, e.g. counting the number of mints and burns by minter address.\n\nThe file [analysis/usdt_frozen_funds.py](analysis/usdt_frozen_funds.py) looks at all the frozen addresses, and gets their USDT balance at the time of their freeze.\n\n## Who's in charge?\n\nAll the functionality of the USDT is controlled by the contract owner [0xC6CDE7C39eB2f0F0095F41570af89eFC2C1Ea828](https://etherscan.io/address/0xC6CDE7C39eB2f0F0095F41570af89eFC2C1Ea828).\nThis means that there is no separation of roles, the same (3-out-of-6) multisig account is in control of issuing, redeeming, blacklisting, clawbacks and pausing.  This is a violation of ``[the principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege)'' and is considered bad security practice.\n\n### Minting\n\nUSDT calls the process of \"minting\" new tokens \"issuing.\"\nIssuing new USDT is controlled by the contract owner [0xC6CDE7C39eB2f0F0095F41570af89eFC2C1Ea828](https://etherscan.io/address/0xC6CDE7C39eB2f0F0095F41570af89eFC2C1Ea828).\n\n### Freezing\n\nTether calls the process of freezing an account's USDT \"blacklisting.\"  \n\nTo date, [963 accounts have been frozen](https://bloxy.info/txs/events_sc/0xdac17f958d2ee523a2206206994597c13d831ec7?signature_id=37764)\n\n### Clawbacks\n\nUSDT implements \"clawbacks\" through the \"DestroyBlackFunds\" function ([See Line 291](https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7#code#L291)).\nAs the name implies, Tether only has the ability to remove funds from users that were previously \"blacklisted.\"  Thus a clawback is a two-step process, first the address \nmust be frozen, and only then can the funds be removed.  This is not much of a barrier to clawbacks since both steps of the process are controlled by the same address (the owner), \nand both steps can be incorporated into a single transaction.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbhemen%2Fusdt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbhemen%2Fusdt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbhemen%2Fusdt/lists"}