Skip to content

Open in Remix has encoding error for some contracts #662

@ericglau

Description

@ericglau

From https://wizard.openzeppelin.com/#account , leave the defaults selected, then add "Modules" so that the options appear as shown:

Screenshot Image

This results in the code:

Solidity code
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.4.0
pragma solidity ^0.8.27;

import {AbstractSigner} from "@openzeppelin/contracts/utils/cryptography/signers/AbstractSigner.sol";
import {Account} from "@openzeppelin/contracts/account/Account.sol";
import {AccountERC7579} from "@openzeppelin/contracts/account/extensions/draft-AccountERC7579.sol";
import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import {ERC7739} from "@openzeppelin/contracts/utils/cryptography/signers/draft-ERC7739.sol";
import {PackedUserOperation} from "@openzeppelin/contracts/interfaces/draft-IERC4337.sol";
import {SignerECDSA} from "@openzeppelin/contracts/utils/cryptography/signers/SignerECDSA.sol";

contract MyAccount is Account, EIP712, ERC7739, AccountERC7579, SignerECDSA, ERC721Holder, ERC1155Holder {
    constructor(address signer) EIP712("MyAccount", "1") SignerECDSA(signer) {}

    function isValidSignature(bytes32 hash, bytes calldata signature)
        public
        view
        override(AccountERC7579, ERC7739)
        returns (bytes4)
    {
        // ERC-7739 can return the ERC-1271 magic value, 0xffffffff (invalid) or 0x77390001 (detection).
        // If the returned value is 0xffffffff, fallback to ERC-7579 validation.
        bytes4 erc7739magic = ERC7739.isValidSignature(hash, signature);
        return erc7739magic == bytes4(0xffffffff) ? AccountERC7579.isValidSignature(hash, signature) : erc7739magic;
    }

    // The following functions are overrides required by Solidity.

    function _validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash)
        internal
        override(Account, AccountERC7579)
        returns (uint256)
    {
        return super._validateUserOp(userOp, userOpHash);
    }

    // IMPORTANT: Make sure SignerECDSA is most derived than AccountERC7579
    // in the inheritance chain (i.e. contract ... is AccountERC7579, ..., SignerECDSA)
    // to ensure the correct order of function resolution.
    // AccountERC7579 returns false for _rawSignatureValidation
    function _rawSignatureValidation(bytes32 hash, bytes calldata signature)
        internal
        view
        override(SignerECDSA, AbstractSigner, AccountERC7579)
        returns (bool)
    {
        return super._rawSignatureValidation(hash, signature);
    }
}

This results in the following encoded URL:
https://remix.ethereum.org/?code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVAovLyBDb21wYXRpYmxlIHdpdGggT3BlblplcHBlbGluIENvbnRyYWN0cyBeNS40LjAKcHJhZ21hIHNvbGlkaXR5IF4wLjguMjc7CgppbXBvcnQge0Fic3RyYWN0U2lnbmVyfSBmcm9tICJAb3BlbnplcHBlbGluL2NvbnRyYWN0c0A1LjQuMC91dGlscy9jcnlwdG9ncmFwaHkvc2lnbmVycy9BYnN0cmFjdFNpZ25lci5zb2wiOwppbXBvcnQge0FjY291bnR9IGZyb20gIkBvcGVuemVwcGVsaW4vY29udHJhY3RzQDUuNC4wL2FjY291bnQvQWNjb3VudC5zb2wiOwppbXBvcnQge0FjY291bnRFUkM3NTc5fSBmcm9tICJAb3BlbnplcHBlbGluL2NvbnRyYWN0c0A1LjQuMC9hY2NvdW50L2V4dGVuc2lvbnMvZHJhZnQtQWNjb3VudEVSQzc1Nzkuc29sIjsKaW1wb3J0IHtFSVA3MTJ9IGZyb20gIkBvcGVuemVwcGVsaW4vY29udHJhY3RzQDUuNC4wL3V0aWxzL2NyeXB0b2dyYXBoeS9FSVA3MTIuc29sIjsKaW1wb3J0IHtFUkMxMTU1SG9sZGVyfSBmcm9tICJAb3BlbnplcHBlbGluL2NvbnRyYWN0c0A1LjQuMC90b2tlbi9FUkMxMTU1L3V0aWxzL0VSQzExNTVIb2xkZXIuc29sIjsKaW1wb3J0IHtFUkM3MjFIb2xkZXJ9IGZyb20gIkBvcGVuemVwcGVsaW4vY29udHJhY3RzQDUuNC4wL3Rva2VuL0VSQzcyMS91dGlscy9FUkM3MjFIb2xkZXIuc29sIjsKaW1wb3J0IHtFUkM3NzM5fSBmcm9tICJAb3BlbnplcHBlbGluL2NvbnRyYWN0c0A1LjQuMC91dGlscy9jcnlwdG9ncmFwaHkvc2lnbmVycy9kcmFmdC1FUkM3NzM5LnNvbCI7CmltcG9ydCB7UGFja2VkVXNlck9wZXJhdGlvbn0gZnJvbSAiQG9wZW56ZXBwZWxpbi9jb250cmFjdHNANS40LjAvaW50ZXJmYWNlcy9kcmFmdC1JRVJDNDMzNy5zb2wiOwppbXBvcnQge1NpZ25lckVDRFNBfSBmcm9tICJAb3BlbnplcHBlbGluL2NvbnRyYWN0c0A1LjQuMC91dGlscy9jcnlwdG9ncmFwaHkvc2lnbmVycy9TaWduZXJFQ0RTQS5zb2wiOwoKY29udHJhY3QgTXlBY2NvdW50IGlzIEFjY291bnQsIEVJUDcxMiwgRVJDNzczOSwgQWNjb3VudEVSQzc1NzksIFNpZ25lckVDRFNBLCBFUkM3MjFIb2xkZXIsIEVSQzExNTVIb2xkZXIgewogICAgY29uc3RydWN0b3IoYWRkcmVzcyBzaWduZXIpIEVJUDcxMigiTXlBY2NvdW50IiwgIjEiKSBTaWduZXJFQ0RTQShzaWduZXIpIHt9CgogICAgZnVuY3Rpb24gaXNWYWxpZFNpZ25hdHVyZShieXRlczMyIGhhc2gsIGJ5dGVzIGNhbGxkYXRhIHNpZ25hdHVyZSkKICAgICAgICBwdWJsaWMKICAgICAgICB2aWV3CiAgICAgICAgb3ZlcnJpZGUoQWNjb3VudEVSQzc1NzksIEVSQzc3MzkpCiAgICAgICAgcmV0dXJucyAoYnl0ZXM0KQogICAgewogICAgICAgIC8vIEVSQy03NzM5IGNhbiByZXR1cm4gdGhlIEVSQy0xMjcxIG1hZ2ljIHZhbHVlLCAweGZmZmZmZmZmIChpbnZhbGlkKSBvciAweDc3MzkwMDAxIChkZXRlY3Rpb24pLgogICAgICAgIC8vIElmIHRoZSByZXR1cm5lZCB2YWx1ZSBpcyAweGZmZmZmZmZmLCBmYWxsYmFjayB0byBFUkMtNzU3OSB2YWxpZGF0aW9uLgogICAgICAgIGJ5dGVzNCBlcmM3NzM5bWFnaWMgPSBFUkM3NzM5LmlzVmFsaWRTaWduYXR1cmUoaGFzaCwgc2lnbmF0dXJlKTsKICAgICAgICByZXR1cm4gZXJjNzczOW1hZ2ljID09IGJ5dGVzNCgweGZmZmZmZmZmKSA%2FIEFjY291bnRFUkM3NTc5LmlzVmFsaWRTaWduYXR1cmUoaGFzaCwgc2lnbmF0dXJlKSA6IGVyYzc3MzltYWdpYzsKICAgIH0KCiAgICAvLyBUaGUgZm9sbG93aW5nIGZ1bmN0aW9ucyBhcmUgb3ZlcnJpZGVzIHJlcXVpcmVkIGJ5IFNvbGlkaXR5LgoKICAgIGZ1bmN0aW9uIF92YWxpZGF0ZVVzZXJPcChQYWNrZWRVc2VyT3BlcmF0aW9uIGNhbGxkYXRhIHVzZXJPcCwgYnl0ZXMzMiB1c2VyT3BIYXNoKQogICAgICAgIGludGVybmFsCiAgICAgICAgb3ZlcnJpZGUoQWNjb3VudCwgQWNjb3VudEVSQzc1NzkpCiAgICAgICAgcmV0dXJucyAodWludDI1NikKICAgIHsKICAgICAgICByZXR1cm4gc3VwZXIuX3ZhbGlkYXRlVXNlck9wKHVzZXJPcCwgdXNlck9wSGFzaCk7CiAgICB9CgogICAgLy8gSU1QT1JUQU5UOiBNYWtlIHN1cmUgU2lnbmVyRUNEU0EgaXMgbW9zdCBkZXJpdmVkIHRoYW4gQWNjb3VudEVSQzc1NzkKICAgIC8vIGluIHRoZSBpbmhlcml0YW5jZSBjaGFpbiAoaS5lLiBjb250cmFjdCAuLi4gaXMgQWNjb3VudEVSQzc1NzksIC4uLiwgU2lnbmVyRUNEU0EpCiAgICAvLyB0byBlbnN1cmUgdGhlIGNvcnJlY3Qgb3JkZXIgb2YgZnVuY3Rpb24gcmVzb2x1dGlvbi4KICAgIC8vIEFjY291bnRFUkM3NTc5IHJldHVybnMgZmFsc2UgZm9yIF9yYXdTaWduYXR1cmVWYWxpZGF0aW9uCiAgICBmdW5jdGlvbiBfcmF3U2lnbmF0dXJlVmFsaWRhdGlvbihieXRlczMyIGhhc2gsIGJ5dGVzIGNhbGxkYXRhIHNpZ25hdHVyZSkKICAgICAgICBpbnRlcm5hbAogICAgICAgIHZpZXcKICAgICAgICBvdmVycmlkZShTaWduZXJFQ0RTQSwgQWJzdHJhY3RTaWduZXIsIEFjY291bnRFUkM3NTc5KQogICAgICAgIHJldHVybnMgKGJvb2wpCiAgICB7CiAgICAgICAgcmV0dXJuIHN1cGVyLl9yYXdTaWduYXR1cmVWYWxpZGF0aW9uKGhhc2gsIHNpZ25hdHVyZSk7CiAgICB9Cn0K#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVAovLyBDb21wYXRpYmxlIHdpdGggT3BlblplcHBlbGluIENvbnRyYWN0cyBeNS40LjAKcHJhZ21hIHNvbGlkaXR5IF4wLjguMjc7CgppbXBvcnQge0Fic3RyYWN0U2lnbmVyfSBmcm9tICJAb3BlbnplcHBlbGluL2NvbnRyYWN0c0A1LjQuMC91dGlscy9jcnlwdG9ncmFwaHkvc2lnbmVycy9BYnN0cmFjdFNpZ25lci5zb2wiOwppbXBvcnQge0FjY291bnR9IGZyb20gIkBvcGVuemVwcGVsaW4vY29udHJhY3RzQDUuNC4wL2FjY291bnQvQWNjb3VudC5zb2wiOwppbXBvcnQge0FjY291bnRFUkM3NTc5fSBmcm9tICJAb3BlbnplcHBlbGluL2NvbnRyYWN0c0A1LjQuMC9hY2NvdW50L2V4dGVuc2lvbnMvZHJhZnQtQWNjb3VudEVSQzc1Nzkuc29sIjsKaW1wb3J0IHtFSVA3MTJ9IGZyb20gIkBvcGVuemVwcGVsaW4vY29udHJhY3RzQDUuNC4wL3V0aWxzL2NyeXB0b2dyYXBoeS9FSVA3MTIuc29sIjsKaW1wb3J0IHtFUkMxMTU1SG9sZGVyfSBmcm9tICJAb3BlbnplcHBlbGluL2NvbnRyYWN0c0A1LjQuMC90b2tlbi9FUkMxMTU1L3V0aWxzL0VSQzExNTVIb2xkZXIuc29sIjsKaW1wb3J0IHtFUkM3MjFIb2xkZXJ9IGZyb20gIkBvcGVuemVwcGVsaW4vY29udHJhY3RzQDUuNC4wL3Rva2VuL0VSQzcyMS91dGlscy9FUkM3MjFIb2xkZXIuc29sIjsKaW1wb3J0IHtFUkM3NzM5fSBmcm9tICJAb3BlbnplcHBlbGluL2NvbnRyYWN0c0A1LjQuMC91dGlscy9jcnlwdG9ncmFwaHkvc2lnbmVycy9kcmFmdC1FUkM3NzM5LnNvbCI7CmltcG9ydCB7UGFja2VkVXNlck9wZXJhdGlvbn0gZnJvbSAiQG9wZW56ZXBwZWxpbi9jb250cmFjdHNANS40LjAvaW50ZXJmYWNlcy9kcmFmdC1JRVJDNDMzNy5zb2wiOwppbXBvcnQge1NpZ25lckVDRFNBfSBmcm9tICJAb3BlbnplcHBlbGluL2NvbnRyYWN0c0A1LjQuMC91dGlscy9jcnlwdG9ncmFwaHkvc2lnbmVycy9TaWduZXJFQ0RTQS5zb2wiOwoKY29udHJhY3QgTXlBY2NvdW50IGlzIEFjY291bnQsIEVJUDcxMiwgRVJDNzczOSwgQWNjb3VudEVSQzc1NzksIFNpZ25lckVDRFNBLCBFUkM3MjFIb2xkZXIsIEVSQzExNTVIb2xkZXIgewogICAgY29uc3RydWN0b3IoYWRkcmVzcyBzaWduZXIpIEVJUDcxMigiTXlBY2NvdW50IiwgIjEiKSBTaWduZXJFQ0RTQShzaWduZXIpIHt9CgogICAgZnVuY3Rpb24gaXNWYWxpZFNpZ25hdHVyZShieXRlczMyIGhhc2gsIGJ5dGVzIGNhbGxkYXRhIHNpZ25hdHVyZSkKICAgICAgICBwdWJsaWMKICAgICAgICB2aWV3CiAgICAgICAgb3ZlcnJpZGUoQWNjb3VudEVSQzc1NzksIEVSQzc3MzkpCiAgICAgICAgcmV0dXJucyAoYnl0ZXM0KQogICAgewogICAgICAgIC8vIEVSQy03NzM5IGNhbiByZXR1cm4gdGhlIEVSQy0xMjcxIG1hZ2ljIHZhbHVlLCAweGZmZmZmZmZmIChpbnZhbGlkKSBvciAweDc3MzkwMDAxIChkZXRlY3Rpb24pLgogICAgICAgIC8vIElmIHRoZSByZXR1cm5lZCB2YWx1ZSBpcyAweGZmZmZmZmZmLCBmYWxsYmFjayB0byBFUkMtNzU3OSB2YWxpZGF0aW9uLgogICAgICAgIGJ5dGVzNCBlcmM3NzM5bWFnaWMgPSBFUkM3NzM5LmlzVmFsaWRTaWduYXR1cmUoaGFzaCwgc2lnbmF0dXJlKTsKICAgICAgICByZXR1cm4gZXJjNzczOW1hZ2ljID09IGJ5dGVzNCgweGZmZmZmZmZmKSA%2FIEFjY291bnRFUkM3NTc5LmlzVmFsaWRTaWduYXR1cmUoaGFzaCwgc2lnbmF0dXJlKSA6IGVyYzc3MzltYWdpYzsKICAgIH0KCiAgICAvLyBUaGUgZm9sbG93aW5nIGZ1bmN0aW9ucyBhcmUgb3ZlcnJpZGVzIHJlcXVpcmVkIGJ5IFNvbGlkaXR5LgoKICAgIGZ1bmN0aW9uIF92YWxpZGF0ZVVzZXJPcChQYWNrZWRVc2VyT3BlcmF0aW9uIGNhbGxkYXRhIHVzZXJPcCwgYnl0ZXMzMiB1c2VyT3BIYXNoKQogICAgICAgIGludGVybmFsCiAgICAgICAgb3ZlcnJpZGUoQWNjb3VudCwgQWNjb3VudEVSQzc1NzkpCiAgICAgICAgcmV0dXJucyAodWludDI1NikKICAgIHsKICAgICAgICByZXR1cm4gc3VwZXIuX3ZhbGlkYXRlVXNlck9wKHVzZXJPcCwgdXNlck9wSGFzaCk7CiAgICB9CgogICAgLy8gSU1QT1JUQU5UOiBNYWtlIHN1cmUgU2lnbmVyRUNEU0EgaXMgbW9zdCBkZXJpdmVkIHRoYW4gQWNjb3VudEVSQzc1NzkKICAgIC8vIGluIHRoZSBpbmhlcml0YW5jZSBjaGFpbiAoaS5lLiBjb250cmFjdCAuLi4gaXMgQWNjb3VudEVSQzc1NzksIC4uLiwgU2lnbmVyRUNEU0EpCiAgICAvLyB0byBlbnN1cmUgdGhlIGNvcnJlY3Qgb3JkZXIgb2YgZnVuY3Rpb24gcmVzb2x1dGlvbi4KICAgIC8vIEFjY291bnRFUkM3NTc5IHJldHVybnMgZmFsc2UgZm9yIF9yYXdTaWduYXR1cmVWYWxpZGF0aW9uCiAgICBmdW5jdGlvbiBfcmF3U2lnbmF0dXJlVmFsaWRhdGlvbihieXRlczMyIGhhc2gsIGJ5dGVzIGNhbGxkYXRhIHNpZ25hdHVyZSkKICAgICAgICBpbnRlcm5hbAogICAgICAgIHZpZXcKICAgICAgICBvdmVycmlkZShTaWduZXJFQ0RTQSwgQWJzdHJhY3RTaWduZXIsIEFjY291bnRFUkM3NTc5KQogICAgICAgIHJldHVybnMgKGJvb2wpCiAgICB7CiAgICAgICAgcmV0dXJuIHN1cGVyLl9yYXdTaWduYXR1cmVWYWxpZGF0aW9uKGhhc2gsIHNpZ25hdHVyZSk7CiAgICB9Cn0K

The contract does not appear in Remix. From the browser console when on Remix, the following error is seen:

InvalidCharacterError: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.
    at decodePercentEscapedBase64 (workspace.ts:281:25)
    at _callee18$ (workspace.ts:307:19)
    at tryCatch (regeneratorRuntime.js:45:16)
    at Generator.<anonymous> (regeneratorRuntime.js:133:17)
    at Generator.next (regeneratorRuntime.js:74:21)
    at asyncGeneratorStep (asyncToGenerator.js:3:15)
    at _next (asyncToGenerator.js:17:9)
    at asyncToGenerator.js:22:7
    at new Promise (<anonymous>)
    at asyncToGenerator.js:14:12

We should investigate whether the above URL is encoded correctly in Wizard, and/or whether it is being decoded correctly from Remix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions