Created
June 25, 2022 16:22
-
-
Save raddy/252fcb7f3cbb841d65f5cf2450736bd4 to your computer and use it in GitHub Desktop.
Fetch allowances slot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
const { ethers } = require("ethers"); | |
const { formatUnits } = require("@ethersproject/units"); | |
const { program } = require("commander"); | |
const erc20Abi = require("./erc20.json"); | |
const storage = async ( | |
provider, | |
tokenAddress, | |
k | |
) => { | |
return ethers.BigNumber.from( | |
await provider.getStorageAt( | |
tokenAddress, | |
k | |
) | |
); | |
}; | |
const key = async ( | |
user, | |
contractAddress, | |
slot | |
) => { | |
const innerCalc = ethers.utils.solidityKeccak256( | |
["uint256", "uint256"], | |
[user, slot] | |
); | |
return ethers.utils.solidityKeccak256( | |
["uint256", "uint256"], | |
[contractAddress, innerCalc] | |
); | |
}; | |
const search = async ( | |
user, | |
tokenAddress, | |
target, | |
rpc, | |
max | |
) => { | |
const provider = new ethers.providers.JsonRpcProvider(rpc); | |
const token = new ethers.Contract(tokenAddress, erc20Abi, provider); | |
let tokenSymbol = tokenAddress; | |
let tokenDecimals = 18; | |
try { | |
tokenDecimals = await token.decimals(); | |
tokenSymbol = await token.symbol(); | |
} catch (e) { | |
// Fuck it | |
} | |
// Get the actual allowance | |
const allowance = await token.allowance(user, target); | |
console.log(`User ${user} approved ${formatUnits( | |
allowance, | |
tokenDecimals | |
)} ${tokenSymbol} tokens to ${target}`); | |
for (let i = 0; i <= max; i++) { | |
const k = await key(user, target, i); | |
const v = await storage(provider, tokenAddress, k); | |
if (v.eq(allowance)) { | |
console.log(`Slot ${i} of ${tokenSymbol} matches ${allowance}`); | |
return; | |
} | |
else { | |
console.log(`Slot ${i} of ${tokenSymbol} did not match ${allowance}`) | |
} | |
} | |
}; | |
const main = async () => { | |
program | |
.argument("<user>", "User address") | |
.argument("<token>", "ERC20 token") | |
.argument("<target>", "Target Contract") | |
.option("--rpc <url>", "RPC URL", "http://127.0.0.1:8545") | |
.option("--max <max>", "Max Slot to Test", 15) | |
.action(async (user, tokenAddress, target, options) => { | |
await search( | |
user, | |
tokenAddress, | |
target, | |
options.rpc, | |
parseInt(options.max) | |
); | |
}); | |
program.parseAsync(); | |
}; | |
main().catch((e) => console.error(e.toString())); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment