circlefin / stablecoin-evm

Source repository for smart contracts used by Circle's stablecoins on EVM-compatible blockchains
Apache License 2.0
544 stars 330 forks source link

Permit Signature checker only accepts Smart wallet signatures from deployed contracts #470

Open Ncastro878 opened 1 month ago

Ncastro878 commented 1 month ago

Hello, my team is working on an app that primarily uses USDC and we are attempting to integrate the new coinbase Smart Wallets into our app. We utilize the permit function for off-chain gasless approvals for users, through which the user will sign an eip712 message that will authorize an allowance for their usdc tokens.

The issue we ran into is that the permit signature was not accepted for brand new created coinbase smart wallets, but i think this applies to smart wallets in general maybe.

It seems when the signature is submitted to USDC erc20 contract it gets a failing EOA signature error. I found the code i believe fails and it seems the SignatureChecker expects a smart wallets code to be deployed to the blockchain. However, from what I read the smart wallet code is deployed when the owner first initiates a transaction from the wallet. So new wallets that may have received tokens can not have their signed messages approved.

Link to code: https://github.com/circlefin/stablecoin-evm/blob/f64f01f93ea4e4b3a88be1de716fc0ada88f798c/contracts/util/SignatureChecker.sol#L43C14-L43C24

I'm reading more into offchain signature verification for undeployed smart wallets, erc-6492

This is my first issue submission. What steps would need to be taken to bring this change about?

Edit: off the top of my head, i wonder if updating the conditional w/ isContract to also check if the signature ends with the predeploy magic bytes (0x6492649264926492649264926492649264926492649264926492649264926492) may be a suitable check to init a smart wallet signature check; I can attempt an example PR tomorrow to demonstrate

Ncastro878 commented 4 weeks ago

i don't have permissions to create a PR (understandably so). But something like this may suffice.


    function isValidSignatureNow(
        address signer,
        bytes32 digest,
        bytes memory signature
    ) external view returns (bool) {
        if (!isContract(signer) && !isCounterfactual(signature)) { // <--- Additional check here
            return ECRecover.recover(digest, signature) == signer;
        }
        return isValidERC1271SignatureNow(signer, digest, signature);
    }
    ...

   /**
     * @dev Checks if the signature is a predeploy counterfactual signature per eip-6492
     * link: https://eips.ethereum.org/EIPS/eip-6492
     */
    function isCounterfactual(bytes memory _signature) internal pure returns (bool) {
        bytes32 ERC6492_DETECTION_SUFFIX = 0x6492649264926492649264926492649264926492649264926492649264926492;
        return bytes32(_signature[_signature.length-32:_signature.length]) == ERC6492_DETECTION_SUFFIX;
    }