【问题标题】:Solidity & Web3js: EIP712 signing uint256 works signing uint256[] does notSolidity & Web3js:EIP712 签名 uint256 工作签名 uint256[] 不
【发布时间】:2020-02-04 00:50:49
【问题描述】:

我正在用EIP712签署订单,并且我在签署uint256时实现了恢复数据,一旦我使用uint256[],它就会恢复到错误的地址。

有人可以帮忙吗?

这是创建签名 (web3js) 的 javascript 方面:

var domain = [
  { name: "name", type: "string" },
  { name: "version", type: "string" },
  { name: "chainId", type: "uint256" },
  { name: "verifyingContract", type: "address" },
  { name: "salt", type: "bytes32" }
];
var sellOrders = [
  { name: "id", type: "uint256[]" },
  { name: "tokenId", type: "uint256[]" },
  { name: "price", type: "uint256[]" },
  { name: "proto", type: "uint256[]" },
  { name: "purity", type: "uint256[]" },
  { name: "seller", type: "address" }
];
const domainData = {
  name: "app",
  version: "1",
  chainId: 3,
  verifyingContract: cardExchangeContract,
  salt: "0xa222082684812afae4e093416fff16bc218b569abe4db590b6a058e1f2c1cd3e"
};
var message = {
  id: [1],
  tokenId: [1],
  price: [1],
  proto: [1],
  purity: [1],
  seller: address
};
var data = JSON.stringify({
  types: {
      EIP712Domain: domain,
      SellOrders: sellOrders,
  },
  domain: domainData,
  primaryType: "SellOrders",
  message: message
});
window.web3.currentProvider.sendAsync({
  method: "eth_signTypedData_v4",
  params: [address, data],
  from: address
}, function(error, result) {
  if (error) { 
    errorCallback(); 
  } else {
    const signature = result.result.substring(2);
    const r = "0x" + signature.substring(0, 64);
    const s = "0x" + signature.substring(64, 128);
    const v = parseInt(signature.substring(128, 130), 16);
    successCallback(signature, r, s, v);
  }
});

这里是坚固的一面:

string private constant domain = "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)";
bytes32 public constant domainTypeHash = keccak256(abi.encodePacked(domain));
string private constant sellOrdersType = "SellOrders(uint256[] id,uint256[] tokenId,uint256[] price,uint256[] proto,uint256[] purity,address seller)";
bytes32 public constant sellOrdersTypeHash = keccak256(abi.encodePacked(sellOrdersType));
uint256 constant chainId = 3;
bytes32 constant salt = 0xa222082684812afae4e093416fff16bc218b569abe4db590b6a058e1f2c1cd3e;
bytes32 private domainSeparator;

struct SellOrders {
    uint256[] id;
    uint256[] tokenId;
    uint256[] price;
    uint256[] proto;
    uint256[] purity;
    address payable seller;
}

constructor() public {
    domainSeparator = keccak256(abi.encode(
        domainTypeHash,
        keccak256("app"),
        keccak256("1"), // version
        chainId,
        this,
        salt
    ));
}

function recover(uint256[] calldata id, uint256[] calldata tokenId, uint256[] calldata price, uint256[] calldata proto, uint256[] calldata purity, address seller, uint8 v, bytes32 r, bytes32 s) external view returns (address) {
    return _recover(id, tokenId, price, proto, purity, seller, v, r, s);
}
function _recover(uint256[] memory id, uint256[] memory tokenId, uint256[] memory price, uint256[] memory proto, uint256[] memory purity, address seller, uint8 v, bytes32 r, bytes32 s) private view returns (address) {
    return ecrecover(hashSellOrders(id, tokenId, price, proto, purity, seller), v, r, s);
}
function hashSellOrders(uint256[] memory id, uint256[] memory tokenId, uint256[] memory price, uint256[] memory proto, uint256[] memory purity, address seller) private view returns (bytes32){
    return keccak256(abi.encodePacked(
       "\x19\x01",
       domainSeparator,
       keccak256(abi.encode(
            sellOrdersTypeHash,
            id,
            tokenId,
            price,
            proto,
            purity,
            seller
        ))
    ));
}

当我将 sellOrders 属性更改为 uint256 而不是 uint256[] 并提供 uint256s 而不是数组时,它会按预期工作,并恢复正确的地址。当我设置它uint256[] 并提供数组时,它会恢复到错误的地址。

编辑/添加

实际工作的代码sn-ps,当使用uint256(无数组)时:

Javascript (web3js/Metamask):

var sellOrders = [
  { name: "id", type: "uint256" },
  { name: "tokenId", type: "uint256" },
  { name: "price", type: "uint256" },
  { name: "proto", type: "uint256" },
  { name: "purity", type: "uint256" },
  { name: "seller", type: "address" }
];

var message = {
  id: 1,
  tokenId: 1,
  price: 1,
  proto: 1,
  purity: 1,
  seller: address
};

坚固性:

string private constant sellOrdersType = "SellOrders(uint256 id,uint256 tokenId,uint256 price,uint256 proto,uint256 purity,address seller)";

struct SellOrders {
    uint256 id;
    uint256 tokenId;
    uint256 price;
    uint256 proto;
    uint256 purity;
    address payable seller;
}

function recover(uint256 id, uint256 tokenId, uint256 price, uint256 proto, uint256 purity, address seller, uint8 v, bytes32 r, bytes32 s) external view returns (address) {
    return _recover(id, tokenId, price, proto, purity, seller, v, r, s);
}
function _recover(uint256 id, uint256 tokenId, uint256 price, uint256 proto, uint256 purity, address seller, uint8 v, bytes32 r, bytes32 s) private view returns (address) {
    return ecrecover(hashSellOrders(id, tokenId, price, proto, purity, seller), v, r, s);
}
function hashSellOrders(uint256 id, uint256 tokenId, uint256 price, uint256 proto, uint256 purity, address seller) private view returns (bytes32){
    return keccak256(abi.encodePacked(
       "\x19\x01",
       domainSeparator,
       keccak256(abi.encode(
            sellOrdersTypeHash,
            id,
            tokenId,
            price,
            proto,
            purity,
            seller
        ))
    ));
}

添加了 2 个 我的最后一项研究将我引向https://github.com/MetaMask/eth-sig-util/blob/master/index.js#L70-L78 Metamask 在客户端实现编码/散列的方式,但我仍然无法在solidity 合约中重现这一点以正确恢复它。

【问题讨论】:

  • 我想我看到了问题,但只是为了确定你能发布两个版本的代码(工作和不工作)吗?谢谢
  • 将代码添加到原始问题中。

标签: ethereum solidity smartcontracts web3js


【解决方案1】:

来自https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#definition-of-encodedata

数组值被编码为其内容的串联encodeDatakeccak256 哈希(即SomeType[5] 的编码与包含五个SomeType 类型成员的结构的编码相同)。

所以我相信这应该可行(完全未经测试):

function hashSellOrders(uint256[] memory id, uint256[] memory tokenId, uint256[] memory price, uint256[] memory proto, uint256[] memory purity, address seller) private view returns (bytes32){
    return keccak256(abi.encodePacked(
       "\x19\x01",
       domainSeparator,
       keccak256(abi.encode(
            sellOrdersTypeHash,
            keccak256(abi.encodePacked(id)),
            keccak256(abi.encodePacked(tokenId)),
            keccak256(abi.encodePacked(price)),
            keccak256(abi.encodePacked(proto)),
            keccak256(abi.encodePacked(purity)),
            seller
        ))
    ));
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-05
    • 2022-08-06
    • 2018-11-25
    • 2018-08-20
    • 1970-01-01
    • 2021-12-15
    • 2022-01-05
    • 2015-09-07
    相关资源
    最近更新 更多