首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从ECDSA.recover()获取错误地址

从ECDSA.recover()获取错误地址
EN

Ethereum用户
提问于 2021-09-06 10:04:13
回答 1查看 1.4K关注 0票数 8

我正在使用醚的_signTypedData()方法对类型化数据进行签名。但是当我使用ECDSA.recover()在Smart契约中检索签名者的地址时,它会返回错误的地址。如果我错过了什么或者采取了错误的方法,请告诉我。我真的很感谢你的帮助!

前端代码

代码语言:javascript
复制
let token = {
    tokenId: 1,
    account: "<< my_wallet_address >>"
};
const provider = new ethers.providers.Web3Provider(window.ethereum);
let signature;
let oContract = new ethers.Contract(CONTRACT_ADDRESS, ABI, provider);
$("#btnSignTransaction").on("click", async function () {
    const signer = provider.getSigner();
    const {
        chainId
    } = await provider.getNetwork();
    signature = await signer._signTypedData({
            name: 'Name',
            version: '1.0.0',
            chainId: chainId,
            verifyingContract: CONTRACT_ADDRESS,
        }, {
            NFT: [{
                    name: 'tokenId',
                    type: 'uint256'
                },
                {
                    name: 'account',
                    type: 'address'
                },
            ],
        },
        token
    );
    token.signature = signature;
});

$("#btnCall").on("click", async function () {
    const addressFromContract = await oContract.getAccountAddress(token.account, token.tokenId, token.signature);
    console.log(addressFromContract);
});

实心码

代码语言:javascript
复制
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; 

contract ERC721LazyMintWith712 is ERC721, EIP712, AccessControl {
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

    constructor(string memory name, string memory symbol)
        ERC721(name, symbol)
        EIP712(name, "1.0.0")
    {
        _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
    }

    function _hash(address account, uint256 tokenId)
        internal
        view
        returns (bytes32)
    {
        return
            _hashTypedDataV4(
                keccak256(
                    abi.encode(
                        keccak256("NFT(uint256 tokenId,address account)"),
                        tokenId,
                        account
                    )
                )
            );
    }

    function _verify(bytes32 digest, bytes memory signature)
        internal
        view
        returns (bool)
    {
        return hasRole(MINTER_ROLE, ECDSA.recover(digest, signature));
    }

    function getAccountAddress(address account, uint256 tokenId, bytes calldata signature) external view returns(address) {
        return ECDSA.recover(_hash(account, tokenId), signature);
    }
}

我正在尝试实现来自回购公司的ERC721LazyMintWith712.solSmart合同。然而,当我通过创建测试用例来测试合同时,它工作得很完美,但是,对于前端集成,它却没有!

EN

回答 1

Ethereum用户

发布于 2022-03-23 21:16:39

我无意中发现了这个问题,并浏览了Ethers.js代码和草案- you 712.sol代码,但结果始终与您相同。

代码是完全正确的,并遵守EIP-712。我最好的猜测是,您可能使用了一个测试块链环境,比如ganache /ganache,它具有非常特殊的行为:

  • RPC返回的networkId默认为1337。
  • 默认情况下,由chainId返回的CHAINID码是1。

用这一行:

代码语言:javascript
复制
const { chainId } = await provider.getNetwork();

实际上,您得到的是networkId,而不是草案- are 712.sol通过block.chainid获得的chainId。因此,不同的Ids导致不同的数据、不同的散列,从而导致不同的签名。

虽然您可以在chainId代码中硬编码1,但最干净的解决方案是在JavaScript上使用--chainId X标志,其中X可以被您选择的chainId (即1337)替换,它将确保RPC chainId和Opcode chainID都是相同的值。

使用ganache-cli --chainId 1337,您的代码可以很好地工作在Remix或MetaMask中,默认情况下,chainId和networkId在RPC和Opcode之间是一致的。

使用问题的第二个正在进行的MetaMask (我假设您正在使用它)是,默认的http://localhost:8545端点假定有一个1337的chainId,这可能不适用于硬帽子或特定的ganache配置,这也可能导致客户端的错误签名,但也应该禁止发送任何tx。要么将节点设置为1337的chainId,要么创建自己的MetaMask端点。

所以你的代码没问题。这无疑是一个配置问题,无论是在MetaMask / Ganache还是如上面所述的硬帽子中。

票数 3
EN
页面原文内容由Ethereum提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://ethereum.stackexchange.com/questions/109449

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档