我使用web3.js尝试签一个元组并获得签名。我正在使用draft-EIP712Upgradeable.sol来散列和恢复输入。我最初查看了下面的链接以获得指导,但所提供的解决方案无效。
我所拥有的可靠代码如下:
struct ticket {
address to;
uint256[] amounts;
bytes32[] merkleProof;
bytes signature;
}
function verifySigner(ticket calldata _ticket) internal view returns (address) {
bytes32 digest = _hash(_ticket);
return ECDSA.recover(digest, _ticket.signature);
}
function _hash(ticket calldata _ticket) internal view returns (bytes32) {
return _hashTypedDataV4(keccak256(abi.encode(
keccak256("ticket(address to,uint256[] amounts,bytes32[] merkleProof)"),
_ticket.to,
keccak256(abi.encodePacked(_ticket.amounts)),
keccak256(abi.encodePacked(_ticket.merkleProof))在java方面,我用Js和Web3.js构建了React。我试图获得签名的代码如下:
Ticket = {
"to": accounts[0], //Account sending the transaction
"amounts": amounts, // Array of values. I used [1,1,1]
"merkleProof": hexProof //Array containing the hex proof using created merkle tree and leaf node for account sending transaction.
};
const structHash = web3.utils.soliditySha3(
{type: "address", value: Ticket.to},
{type: "uint256[]", value: Ticket.amounts},
{type: "bytes32[]", value: Ticket.merkleProof}
);
let signature = await web3.eth.sign(structHash, accounts[0])无论我尝试了什么,我似乎都无法成功地恢复发送交易的帐户的地址。在签名之前,是否需要将域分隔符合并到哈希中?
任何帮助都将不胜感激。我在这事上已经被困了将近一个星期了。
稳固契约中的域设置为:
string private constant SIGNING_DOMAIN = "NFTSig";
string private constant SIGNATURE_VERSION = "1";在Java方面,我没有使用它,我意识到了这一点,但无法确定如何正确使用它。
为了测试我的假设,在使用_hashTypedDataV4()函数之前,Solidty中的struct散列应该与我在js脚本中得到的内容相匹配。即
keccak256(abi.encode(
keccak256("ticket(address to,uint256[] amounts,bytes32[] merkleProof)"),
_ticket.to,
keccak256(abi.encodePacked(_ticket.amounts)),
keccak256(abi.encodePacked(_ticket.merkleProof)应该与我在js中得到的散列匹配,但我不太确定这是真的。
发布于 2022-06-09 04:58:16
好吧,我花了好几个小时才弄明白,但我终于明白了。在阅读了一些EIP712资源之后,这个方法起了作用:
在坚固方面没有任何变化。但是,在Java方面,我使用输入结构和签名域创建了一个类型化数据JSON,如下所示
//Layout Struct types
const domain = [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }
]
const typeTicket = [
{ name: "to", type: "address" },
{ name: "amounts", type: "uint256[]" },
{ name: "merkleProof", type: "bytes32[]" },
]
//Create data structs
const domainData = {
name: "NFTSig",
version: "1",
chainId: await web3.eth.getChainId(),//Come back and hardcode the ID later
verifyingContract: await nftInstance.options.address
};
const Ticket = {
"to": signer,
"amounts": amounts,
"merkleProof": hexProof
};
//Put them together in one data structure
data = {
types: {
EIP712Domain: domain,
Ticket: typeTicket,
},
primaryType: "Ticket",
domain: domainData,
message: Ticket
};一旦我有了这个设置,为了获得签名,我使用获得签名:
prvtKey = xxxxxxxxxxxxxxxxx
const sig = ethSigUtil.signTypedData_v4(Buffer.from(prvtKey, 'hex'), {data});下面是我用来解决这个问题的一些资源:
https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct
https://github.com/MetaMask/eth-sig-util/blob/v4.0.1/src/sign-typed-data.ts#L49
https://magic.link/docs/advanced/blockchains/ethereum/javascript
https://ethereum.stackexchange.com/questions/129707
复制相似问题