A very widespread mistake in the crypto world is to send ERC20 tokens to a contract address. The contracts behave like black holes towards the tokens sent to them. There are many discussions about the possible ways to recover the tokens from contracts (see References), and most deem that practically impossible.
The utility tries to recover accidentially sent ERC20 tokens to a contract address. The program analyzes the contract for the SWE weaknesses and several others and attempts to use one of them to resend the tokens back to the owner.
This software is heavily based on Formal Verification of Smart Contracts: Short Paper. Being a static analyzer, TokenRecovery does not need gas when searching for weaknesses, in contrast to other utilities. e.g. fuzzers. Only when (and if!) TokenRecovery finds a way to bring the locked tokens back to the owner, the owner pays a usual transaction fee for the recovery transaction.
You can download pre-built binaries or build from the source.
TokenRecovery is a command line program. Download the zip file and extract to any folder. The executable is statically linked, no loadable dependancies.
The latest release binaries for Windows and Linux are available here:
Building from source code entails setting up an OCaml development environment. Reserve at least an hour of time and see further down in this document for the particulars.
The utility accepts two command line options, rpc of the EVM-compatible network and the hash of the transaction by which you sent your tokens to the contract. The transaction contains all the data required by the utility to test token recoverability.
$ ./tokenrecovery --rpc https://rpc.ankr.com/eth --txhash 0x692449a8abf787633185716b75869bd87b7419db17434c4b7d354e1d3a8e562f
A list of RPC public endpoints can be found here or here.
What follows is an example of successful recovery on polygon mumbai testnet.
NOTE: To get program help, run
$ tokenrecovery --help
We supply polygon mumbai rpc url (https://rpc-mumbai.maticvigil.com) and transaction hash to the command. The utility analizes the contracts and predicts probability of token recovery from the contract. This can time some time (minutes).
PAY ATTENTION: txhash
should be a transaction hash which transferred tokens from your account to the locking contract. TokenRecovery will refuse to proceed if the hash is not a transfer hash. You can always discover this hash by searching in a respective etherscan site (for example, https://etherscan.com for Ethereum or https://polygonscan.com for Polygon).
To prove the transaction belongs to an account in your ownership, you should provide account's private key. The key is used for two purposes:
- proving account ownership (and, thereby, ownership of locked tokens)
- sending recovery transactions provided the recovery is possible.
After account's ownership of the tokens is proved, an attempt to recover the tokens is made. On success, all the locked tokens are recovered to the owner's account.
To get account private key from Metamask, click on three vertical points and Account details
and then Export private key
:
For cold wallets which never export private keys, the only way to get account private key is to use seed phrase to regenerate the private key of the account. There is an online tool for the derivation: https://iancoleman.io/bip39/
First, put your seed phrase to BIP39 mnemonic field and chose ETH coin:
Then chose BIP44 derivation path:
The utility will create all the addresses and private keys from the seed. Find your address and respective private key:
This section documents how to get set up with a development environment for building TokenRecovery from source code. It is only of interest to people who wish to contribute to TokenRecovery.
The following baseline tooling is required in order to build Clarc from source code:
We would recommend you don't install OCaml from a package manager.
Rather, get set up with OPAM and then let OPAM install the correct version of OCaml as follows:
opam init -c 4.11.1 # if OPAM not yet initialized
opam switch create 4.11.1 # if OPAM already initialized
Once OPAM and OCaml are available, install Dune as follows:
opam install dune
The following OCaml tools and libraries are required in order to build Clarc from source code:
- Alcotest for unit tests
- Cmdliner for the command-line interface
- Cppo for code preprocessing
- Cryptokit for the Keccak-256 hash function
- ISO8601 for date handling
- Num for 128-bit integers
These aforementioned dependencies are all best installed via OPAM:
$ opam install -y alcotest cmdliner cppo cryptokit iso8601 num
$ opam pin add -y recoverytoken https://github.com/ethgeeks/recoverytoken.ml -k git
$ git clone https://github.com/ethgeeks/tokenrecovery.git
$ cd tokenrecovery
$ dune build
$ sudo install _build/default/bin/clarc/tokenrecovery.exe /usr/local/bin/tokenrecovery
We thank Consensys for sponsoring the development of TokenRecovery.
Feature | Type | Status | Notes |
---|---|---|---|
* |
function | ✅ | For two parameters. Without overflow checking. |
+ |
function | ✅ | For two parameters. Without overflow checking. |
- |
function | ✅ | For two parameters. Without underflow checking. |
/ |
function | ✅ | For two parameters. Without division-by-zero checking. |
< |
function | ✅ | |
<= |
function | ✅ | |
> |
function | ✅ | |
>= |
function | ✅ | |
and |
operator | ✅ | For two parameters. |
append |
function | ✅ | |
as-contract |
operator | 🚧 | |
as-max-len? |
operator | 🚧 | |
asserts! |
function | ✅ | |
at-block |
operator | ❌ | Not implemented yet. |
begin |
operator | 🚧 | |
block-height |
keyword | ✅ | |
buff |
literal | ✅ | |
burn-block-height |
keyword | ✅ | |
concat |
function | ✅ | Only for lists. |
contract-call? |
operator | ❌ | Not implemented yet. |
contract-caller |
keyword | ✅ | |
contract-of |
operator | ❌ | Not implemented yet. |
default-to |
function | ✅ | |
err |
function | ✅ | |
false |
literal | ✅ | |
filter |
function | 🚧 | |
fold |
function | 🚧 | |
ft-get-balance |
function | 🚧 | |
ft-mint? |
function | 🚧 | |
ft-transfer? |
function | 🚧 | |
get |
operator | 🚧 | |
get-block-info? |
operator | ❌ | Not implemented yet. |
hash160 |
function | ✅ | |
if |
operator | ✅ | |
impl-trait |
operator | ❌ | Not implemented yet. |
int |
literal | ✅ | |
is-eq |
function | ✅ | For two parameters. |
is-err |
function | ✅ | |
is-in-regtest |
keyword | ✅ | |
is-none |
function | ✅ | |
is-ok |
function | ✅ | |
is-some |
function | ✅ | |
keccak256 |
function | ✅ | |
len |
function | ✅ | Only for literals. |
let |
operator | 🚧 | |
list |
function | ✅ | |
map |
function | 🚧 | |
map-delete |
function | 🚧 | |
map-get? |
function | ✅ | |
map-insert |
function | 🚧 | |
map-set |
function | 🚧 | |
match |
operator | ✅ | |
mod |
function | ✅ | Without division-by-zero checking. |
nft-get-owner? |
function | 🚧 | |
nft-mint? |
function | 🚧 | |
nft-transfer? |
function | 🚧 | |
none |
literal | ✅ | |
not |
function | ✅ | |
ok |
function | ✅ | |
or |
operator | ✅ | For two parameters. |
pow |
function | ✅ | Without overflow checking. |
principal |
literal | 🚧 | |
principal-of? |
function | 🚧 | |
print |
function | ✅ | Only for literals. Without a meaningful return value. |
secp256k1-recover? |
function | ❌ | Not implemented yet. |
secp256k1-verify |
function | ❌ | Not implemented yet. |
sha256 |
function | ✅ | |
sha512 |
function | ❌ | Not implemented yet. |
sha512/256 |
function | ❌ | Not implemented yet. |
some |
function | ✅ | |
sqrti |
function | ❌ | Not implemented yet. |
string |
literal | ✅ | |
stx-burn? |
function | ❌ | Not supported. |
stx-get-balance |
function | ❌ | Not supported. |
stx-liquid-supply |
keyword | ❌ | Not supported. |
stx-transfer? |
function | ❌ | Not supported. |
to-int |
function | 🚧 | |
to-uint |
function | 🚧 | |
true |
literal | ✅ | |
try! |
function | ✅ | |
tuple |
operator | 🚧 | |
tx-sender |
keyword | ✅ | |
uint |
literal | ✅ | |
unwrap! |
function | ✅ | |
unwrap-err! |
function | ✅ | |
unwrap-err-panic |
function | ✅ | |
unwrap-panic |
function | ✅ | |
use-trait |
operator | ❌ | Not implemented yet. |
var-get |
operator | ✅ | |
var-set |
operator | ✅ | |
xor |
function | ✅ |
Legend: ❌ = not supported. 🚧 = work in progress. ✅ = supported.
- https://metamask.zendesk.com/hc/en-us/articles/4404062349979-Accidentally-sending-funds-to-the-wrong-address#:~:text=Unfortunately%2C%20there%20is%20no%20guarantee,some%20function%20on%20the%20blockchain.
- https://forum.openzeppelin.com/t/how-to-recover-tokens-sent-to-the-token-contract-instead-of-a-wallet/17668/4
- https://ethereum.stackexchange.com/questions/34559/i-accidentally-sent-a-token-to-a-token-contract-can-i-get-it-back
- https://community.metamask.io/t/sent-tokens-to-a-contract-address-instead-of-deposit-address-can-i-recover-them/440