Is there a way to check if a certain ERC20 contract address supports the ERC2612 permit
method?
First thing that comes to mind is checking if the contract implements one of these functions:
function nonces(address) public view returns (uint256)
function DOMAIN_SEPARATOR() external view returns (bytes32)
Or perhaps even both of these functions, for better assurance.
It is not clear whether you want to conduct this check onchain of offchain, but both options are viable.
I want to do an offchain check.
Can I do this check with only the target contract address ?
Yes, for example, using web3.js, you, can do something like:
const Web3 = require("web3");
const get_selector = func_signature => Web3.utils.keccak256(func_signature).slice(2, 10);
const func1_selector = get_selector("nonces(address)");
const func2_selector = get_selector("DOMAIN_SEPARATOR()");
async function run() {
const web3 = new Web3(YOUR_NODE_URL);
const bytecode = await web3.eth.getCode(YOUR_CONTRACT_ADDRESS);
if (bytecode.includes(func1_selector) && bytecode.includes(func2_selector))
console.log("ERC2612 supported");
else
console.log("ERC2612 not supported");
if (web3.currentProvider.disconnect)
web3.currentProvider.disconnect();
}
run();
let byteCode = await provider.getCode(tokenAddress);
Why don't i get the exact bytecode from my contract. I get a byteCode that's partially the same.
This is the contract code, if you scroll to the bottom you'll find contract creation code.
This is what byteCode
returns. My provider is connected to Avalanche Fuji
0x608060405234801561001057600080fd5b50600436106100cf5760003560e01c806370a082311161008c57806395d89b411161006657806395d89b41146101a8578063a9059cbb146101b0578063d505accf146101c3578063dd62ed3e146101d857600080fd5b806370a08231146101515780637ecebe001461017a57806384b0196e1461018d57600080fd5b806306fdde03146100d4578063095ea7b3146100f257806318160ddd1461011557806323b872dd14610127578063313ce5671461013a5780633644e51514610149575b600080fd5b6100dc610211565b6040516100e99190610c62565b60405180910390f35b610105610100366004610c98565b6102a3565b60405190151581526020016100e9565b6002545b6040519081526020016100e9565b610105610135366004610cc2565b6102bd565b604051601281526020016100e9565b6101196102e1565b61011961015f366004610cfe565b6001600160a01b031660009081526020819052604090205490565b610119610188366004610cfe565b6102f0565b61019561030e565b6040516100e99796959493929190610d19565b6100dc610354565b6101056101be366004610c98565b610363565b6101d66101d1366004610daf565b610371565b005b6101196101e6366004610e22565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60606003805461022090610e55565b80601f016020809104026020016040519081016040528092919081815260200182805461024c90610e55565b80156102995780601f1061026e57610100808354040283529160200191610299565b820191906000526020600020905b81548152906001019060200180831161027c57829003601f168201915b5050505050905090565b6000336102b18185856104b0565b60019150505b92915050565b6000336102cb8582856104c2565b6102d6858585610540565b506001949350505050565b60006102eb61059f565b905090565b6001600160a01b0381166000908152600760205260408120546102b7565b6000606080600080600060606103226106ca565b61032a6106f7565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b60606004805461022090610e55565b6000336102b1818585610540565b8342111561039a5760405163313c898160e11b8152600481018590526024015b60405180910390fd5b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98888886103e78c6001600160a01b0316600090815260076020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e001604051602081830303815290604052805190602001209050600061044282610724565b9050600061045282878787610751565b9050896001600160a01b0316816001600160a01b031614610499576040516325c0072360e11b81526001600160a01b0380831660048301528b166024820152604401610391565b6104a48a8a8a6104b0565b50505050505050505050565b6104bd838383600161077f565b505050565b6001600160a01b03838116600090815260016020908152604080832093861683529290522054600019811461053a578181101561052b57604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610391565b61053a8484848403600061077f565b50505050565b6001600160a01b03831661056a57604051634b637e8f60e11b815260006004820152602401610391565b6001600160a01b0382166105945760405163ec442f0560e01b815260006004820152602401610391565b6104bd838383610854565b6000306001600160a01b037f000000000000000000000000dcfb5f804dfb67a0fa1c4c802b5d2ad4269618d8161480156105f857507f000000000000000000000000000000000000000000000000000000000000a86946145b1561062257507f7809badea574e77b95db083a8e78900c3fc657049296da38e519e2409f7480c890565b6102eb604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f245c734e6d4ec044daf7beffa09d54d4bafba490113c199734d790b04a7390e5918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60606102eb7f4d79546f6b656e00000000000000000000000000000000000000000000000007600561097e565b60606102eb7f3100000000000000000000000000000000000000000000000000000000000001600661097e565b60006102b761073161059f565b8360405161190160f01b8152600281019290925260228201526042902090565b60008060008061076388888888610a29565b9250925092506107738282610af8565b50909695505050505050565b6001600160a01b0384166107a95760405163e602df0560e01b815260006004820152602401610391565b6001600160a01b0383166107d357604051634a1406b160e11b815260006004820152602401610391565b6001600160a01b038085166000908152600160209081526040808320938716835292905220829055801561053a57826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161084691815260200190565b60405180910390a350505050565b6001600160a01b03831661087f5780600260008282546108749190610e8f565b909155506108f19050565b6001600160a01b038316600090815260208190526040902054818110156108d25760405163391434e360e21b81526001600160a01b03851660048201526024810182905260448101839052606401610391565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b03821661090d5760028054829003905561092c565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161097191815260200190565b60405180910390a3505050565b606060ff83146109985761099183610bb5565b90506102b7565b8180546109a490610e55565b80601f01602080910402602001604051908101604052809291908181526020018280546109d090610e55565b8015610a1d5780601f106109f257610100808354040283529160200191610a1d565b820191906000526020600020905b815481529060010190602001808311610a0057829003601f168201915b505050505090506102b7565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115610a645750600091506003905082610aee565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015610ab8573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610ae457506000925060019150829050610aee565b9250600091508190505b9450945094915050565b6000826003811115610b0c57610b0c610eb0565b03610b15575050565b6001826003811115610b2957610b29610eb0565b03610b475760405163f645eedf60e01b815260040160405180910390fd5b6002826003811115610b5b57610b5b610eb0565b03610b7c5760405163fce698f760e01b815260048101829052602401610391565b6003826003811115610b9057610b90610eb0565b03610bb1576040516335e2f38360e21b815260048101829052602401610391565b5050565b60606000610bc283610bf4565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b600060ff8216601f8111156102b757604051632cd44ac360e21b815260040160405180910390fd5b6000815180845260005b81811015610c4257602081850181015186830182015201610c26565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000610c756020830184610c1c565b9392505050565b80356001600160a01b0381168114610c9357600080fd5b919050565b60008060408385031215610cab57600080fd5b610cb483610c7c565b946020939093013593505050565b600080600060608486031215610cd757600080fd5b610ce084610c7c565b9250610cee60208501610c7c565b9150604084013590509250925092565b600060208284031215610d1057600080fd5b610c7582610c7c565b60ff60f81b881681526000602060e081840152610d3960e084018a610c1c565b8381036040850152610d4b818a610c1c565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b81811015610d9d57835183529284019291840191600101610d81565b50909c9b505050505050505050505050565b600080600080600080600060e0888a031215610dca57600080fd5b610dd388610c7c565b9650610de160208901610c7c565b95506040880135945060608801359350608088013560ff81168114610e0557600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215610e3557600080fd5b610e3e83610c7c565b9150610e4c60208401610c7c565b90509250929050565b600181811c90821680610e6957607f821691505b602082108103610e8957634e487b7160e01b600052602260045260246000fd5b50919050565b808201808211156102b757634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fdfea2646970667358221220629d3ddcff0250b60e07302e0154a11403ca92d4d4bc29704178f9343aae58d264736f6c63430008150033
That's not the same as contract byte code.
The contract creation code includes the input passed upon contract deployment (i.e., the input values passed to the contract's constructor).
The contract byte code does not.
import { keccak256 } from 'js-sha3';
const get_selector = (functionSelector: string) => keccak256(functionSelector).slice(2, 10);
const func1_selector = get_selector("nonces(address)");
const func2_selector = get_selector("DOMAIN_SEPARATOR()");
// func1_selector & func2_selector
-------------------- cebe00bc -------------------
-------------------- 44e51572 -------------------
I didn't get back the hash included in byteCode. I'm sure the contract has these functions.
I get different selectors, namely:
7ecebe00
3644e515
Both of them are in your contract's bytecode.
So the js-sha3
library is probably incompatible with what we're trying to do here.
BTW, the interface also declares function permit:
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
So you might want to extend the script to check the presence of that function as well:
const func3_selector = get_selector("permit(address,address,uint256,uint256,uint8,bytes32,bytes32)");
async function run() {
...
if (
bytecode.includes(func1_selector) &&
bytecode.includes(func2_selector) &&
bytecode.includes(func3_selector)
)
...
}
Yeah I tried using the ethers.utils.keccak256
but it completely fails.
I wonder what the web3 library does under the hood to make it work like that
Appreciate you looking into this!
Change this:
ethers.utils.keccak256("yourInputString")
To this:
ethers.utils.keccak256(ethers.utils.toUtf8Bytes("yourInputString"))
Or to this:
ethers.utils.solidityKeccak256(["string"], ["yourInputString"])
Thanks alot @barakman. This worked perfectly with ethers
.
const func1_selector = ethers.utils.solidityKeccak256(['string'], ["nonces(address)"]).slice(2, 10);
const func2_selector = ethers.utils.solidityKeccak256(['string'], ["DOMAIN_SEPARATOR()"]).slice(2, 10);
const func3_selector = ethers.utils.solidityKeccak256(['string'], ["permit(address,address,uint256,uint256,uint8,bytes32,bytes32)"]).slice(2, 10);