0

I tried to use eip-712 signature with my smart contract but I found out that it only work with fixed-size type. Does anyone know how I can use dynamically-Sized types like string, arrays and bytes

here is a test contract I used,

it works with bytes32 but,

pragma solidity ^0.8.7;

import '@openzeppelin/contracts/utils/cryptography/ECDSA.sol';
import '@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol';

contract SignCheck is EIP712 {
    using ECDSA for bytes32;
    address org;
    struct forwardData {
        address from;
        bytes32 name;
    }

    bytes32 private constant typeHash =
        keccak256(
            'forwardData(address from,bytes32 name)' //here
        );

    constructor(address org_) EIP712('test', '1') {
        org = org_;
    }

    function verify(forwardData calldata data, bytes calldata signature)
        internal
        view
        returns (address)
    {
        return _hashTypedDataV4(
            keccak256(
                abi.encode(typeHash, data.from, data.name)
            )
        ).recover(signature);
    }

    function check(
        forwardData calldata data,
        bytes calldata signature
    ) external view returns (address) {
        return verify(data, signature);
    }
}

in this when I change the type to string, it wont

pragma solidity ^0.8.7;

import '@openzeppelin/contracts/utils/cryptography/ECDSA.sol';
import '@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol';

contract SignCheck is EIP712 {
    using ECDSA for bytes32;
    address org;
    struct forwardData {
        address from;
        string name;
    }

    bytes32 private constant typeHash =
        keccak256(
            'forwardData(address from,string name)' //here
        );

    constructor(address org_) EIP712('test', '1') {
        org = org_;
    }

    function verify(forwardData calldata data, bytes calldata signature)
        internal
        view
        returns (address)
    {
        return _hashTypedDataV4(
            keccak256(
                abi.encode(typeHash, data.from, data.name)
            )
        ).recover(signature);
    }

    function check(
        forwardData calldata data,
        bytes calldata signature
    ) external view returns (address) {
        return verify(data, signature);
    }
}

This is how I implemented ether for this example

const contractAddress = "0x3b1B4DAb15c2222Ae2d30dc835235C990d7d515f";
const inName = "just name";

const domainSeparator = {
  name: "test",
  version: "1",
  // chainId: Number(id_),
  chainId: 1337,
  verifyingContract: contractAddress,
};

const types = {
  forwardData: [
    { name: "from", type: "address" },
    { name: "name", type: "string" },
  ],
};

const value = {
  from: address,
  name: inName,
};

// const digest = TypedDataUtils.encodeDigest(typedData);
const signature = signer._signTypedData(domainSeparator, types, value);

any idea?

1 Answer 1

2

You need to abi.encodePacked and keccak256 the string first.

function verify(forwardData calldata data, bytes calldata signature) internal view returns (address)
{
    return _hashTypedDataV4(
        keccak256(abi.encode(
            typeHash,
            data.from,
            keccak256(abi.encodePacked(data.name)) // Change applied here
        ))
    ).recover(signature);
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.