Skip to content

Instantly share code, notes, and snippets.

@raddy
Created April 3, 2022 15:12
Show Gist options
  • Save raddy/e65bd5bba305e0ff685b2d668fd8bad3 to your computer and use it in GitHub Desktop.
Save raddy/e65bd5bba305e0ff685b2d668fd8bad3 to your computer and use it in GitHub Desktop.
Find allowances slot in an ERC20
#!/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