Scripts to scan all of the UniswapV2π¦ contracts on the Ethereum network and search for mismatched balances/reserves.
UniswapV2 has an interesting function called skim(address)
that lets anyone claim a positive discrepancy between the actual token balance in the contract and the reserve number stored in the Pair contract.
These scripts scan all of the uniV2π¦ contracts to look for those opportunities. Usually there are only a handful, but tokens with changing supplies like aTokens or rebase tokens like AMPL can create some chaos. Most of the skim balances are so small that they aren't worth the gas to call. But sometimes they are profitable.
If you try to call skim from an EOA expect to be frontrun. There are an increasing number of bots searching for these opportunities. You may want to use something like the Forwarder.sol
contract example or even something more sophisticated.
- clone the repo
cd
into the repo- run
npm i
to install the dependencies (web3 and axios)
- there are two main scripts:
uniMarkets.js
scans for any newly deployed markets since the last known Pair and appendslogs/events.js
with any new marketsskim.js
checks every market inlog/events.js
and looks for skim opportunities. It attempts to use the coingecko api to find a price for the value of the skim-able tokens
- from the root of the repo directory
npm run update
will rununiMarket.js
and update the logs to the latest block - from the root of the repo directory
npm run skim
will search for skim-able opportunities
- the scripts are hardcoded to use a local node on port 8546 with a websockets connection. If you are using different ports or infura, change this in the code
- there is a "token blacklist" array that includes tokens that are self-destructed, not actually contracts, or totally non-standard ERC20. This reduces overall errors
- there is a "whitelist" that correctly names tokens who didn't follow the ERC-20 standard and return a byte32 for their name (looking at you MKR). there is probably a smarter way to deal with this edge case than hardcoding but Β―\(γ)/Β―
- if you run into problems updating
events.js
try: A) hardcode the path directory infs.writeFile()
inuniMarkets.js
B) define the block range foreth.getLogs
more narrowly if updating a long time period skim.js
defaults to return skim-able values that are greater than $0.01 so you can see some results. you can change this by altering the variableminDollarVal
inskim.js
. Skim-able values are also returned when coingecko does not have a price for the token (but they have most)events.js
in this repo is current as of block 11057149 and there are 15,230 uniV2π¦ Pairsskim.js
can take a few minutes to run as there are over 15,000 pairs to search!- if
uniMarkets.js
returns no results it's possible that there were no new pairs were deployed since the last time you called the function - the script ignores cases where the reserve is higher than the balance, since that is not skim-able (this happens with rebase coins sometimes)
what your terminal should roughly look like after running npm run update
uniswap-skim npm run update
> [email protected] update /yourDirectory/uniswap-skim
> node ./scripts/uniMarkets.js
π¦ pair #: 9786 deployed in block: 10898080
π¦ pair #: 9787 deployed in block: 10898182
π¦ pair #: 9788 deployed in block: 10898201
π¦ pair #: 9789 deployed in block: 10898327
π¦ pair #: 9790 deployed in block: 10898366
π¦ pair #: 9791 deployed in block: 10898390
what your terminal should roughly look like after running npm run skim
uniswap-skim npm run skim
> [email protected] skim /yourDirectory/uniswap-skim
> node ./scripts/skim.js
{
"pairAddress": "0x321d87e1757c8c9b57e7af5aa3fe13d2ae774445",
"pairIndex": 9355,
"token0": {
"address": "0x29e240cfd7946ba20895a7a02edb25c210f9f324",
"name": "yearn Aave Interest bearing LINK",
"decimals": "18",
"balance": "252,858.663596952206854028",
"reserve": "252,858.663596952206854028",
"imbalance": false
},
"token1": {
"address": "0xa64bd6c70cb9051f6a9ba1f163fdc07e0dfb5f84",
"name": "Aave Interest bearing LINK",
"decimals": "18",
"balance": "267,963.012522435165106136",
"reserve": "267,962.996672942810947153",
"imbalance": {
"diff": "0.015849492360200192",
"usdPrice": 10.35,
"value": "$0.16π¦"
}
}
}
I take no responsibility for any use, misuse, mistakes, or funds lost or received related to the use of this code. Use, modify, ignore as you see fit. There is also a benevolent way to correct uniV2π¦ balance/reserve discrepancies by calling sync()
.
π or π: the choice is yours!