EIP-712 签名消息失败
EIP-712 Signing Messages fails
我有一个修改过的 truffle react box 合约,它应该符合 EIP712 标准:
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.21 <8.10.0;
contract SimpleStorage {
string public constant name = "SimpleStorage";
bytes32 public immutable DOMAIN_SEPARATOR;
bytes32 public constant MESSAGE_HASH =
keccak256("Data(address sender, uint value)");
uint256 storedData;
constructor() {
uint256 chainId;
assembly {
chainId := chainid()
}
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256(
"EIP712Domain(string name,string version,uint256 chainId)"
),
keccak256(bytes(name)),
keccak256(bytes("1")),
chainId
)
);
}
function setPermit(
address sender,
uint256 value,
bytes memory sig
) external {
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(abi.encode(MESSAGE_HASH, sender, value))
)
);
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(sig, 32))
s := mload(add(sig, 64))
v := byte(0, mload(add(sig, 96)))
}
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress == sender, "INVALID_SIGNATURE");
storedData = value;
}
function permit(
address sender,
uint256 value,
uint8 v,
bytes32 r,
bytes32 s
) external {
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(abi.encode(MESSAGE_HASH, sender, value))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(
recoveredAddress != address(0) && recoveredAddress == sender,
"INVALID_SIGNATURE"
);
storedData = value;
}
function set(uint256 x) public {
storedData = x;
}
function get() public view returns (uint256) {
return storedData;
}
}
创建哈希结构和调用合约函数的代码:
signMessage = async () => {
const { web3, accounts, contract, address } = this.state;
var signer = accounts[0];
var value = 50;
const chainId = await web3.eth.getChainId();
const domain = [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
];
const data = [
{ name: "sender", type: "address" },
{ name: "value", type: "uint" },
];
const domainData = {
name: "SimpleStorage",
version: "1",
chainId: chainId,
};
const messageData = {
sender: signer,
value: value,
};
const msgParams = JSON.stringify({
types: {
EIP712Domain: domain,
Data: data,
},
domain: domainData,
primaryType: "Data",
message: messageData,
});
console.log(msgParams);
web3.currentProvider.sendAsync({
method: "eth_signTypedData_v4",
params: [signer, msgParams],
from: signer
}, async function(err, result) {
if(err) { return console.error(err); }
const signResult = result.result;
await contract.methods.setPermit(signer, value, signResult)
.send({ from: signer });
const response = await contract.methods.get().call();
this.setState({ storageValue: response });
});
};
我已经将合约部署到 Rinkeby (0x729352f7541F205226234e3B8C4ABB820c68B380),但每次我尝试使用 setPermit 函数时,我都会在 Metamask 中收到“此交易预计会失败”错误。进一步调查显示,交易fails。我该如何解决这个问题?
经常检查你的数据类型:)
我有一个修改过的 truffle react box 合约,它应该符合 EIP712 标准:
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.21 <8.10.0;
contract SimpleStorage {
string public constant name = "SimpleStorage";
bytes32 public immutable DOMAIN_SEPARATOR;
bytes32 public constant MESSAGE_HASH =
keccak256("Data(address sender, uint value)");
uint256 storedData;
constructor() {
uint256 chainId;
assembly {
chainId := chainid()
}
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256(
"EIP712Domain(string name,string version,uint256 chainId)"
),
keccak256(bytes(name)),
keccak256(bytes("1")),
chainId
)
);
}
function setPermit(
address sender,
uint256 value,
bytes memory sig
) external {
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(abi.encode(MESSAGE_HASH, sender, value))
)
);
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(sig, 32))
s := mload(add(sig, 64))
v := byte(0, mload(add(sig, 96)))
}
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress == sender, "INVALID_SIGNATURE");
storedData = value;
}
function permit(
address sender,
uint256 value,
uint8 v,
bytes32 r,
bytes32 s
) external {
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(abi.encode(MESSAGE_HASH, sender, value))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(
recoveredAddress != address(0) && recoveredAddress == sender,
"INVALID_SIGNATURE"
);
storedData = value;
}
function set(uint256 x) public {
storedData = x;
}
function get() public view returns (uint256) {
return storedData;
}
}
创建哈希结构和调用合约函数的代码:
signMessage = async () => {
const { web3, accounts, contract, address } = this.state;
var signer = accounts[0];
var value = 50;
const chainId = await web3.eth.getChainId();
const domain = [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
];
const data = [
{ name: "sender", type: "address" },
{ name: "value", type: "uint" },
];
const domainData = {
name: "SimpleStorage",
version: "1",
chainId: chainId,
};
const messageData = {
sender: signer,
value: value,
};
const msgParams = JSON.stringify({
types: {
EIP712Domain: domain,
Data: data,
},
domain: domainData,
primaryType: "Data",
message: messageData,
});
console.log(msgParams);
web3.currentProvider.sendAsync({
method: "eth_signTypedData_v4",
params: [signer, msgParams],
from: signer
}, async function(err, result) {
if(err) { return console.error(err); }
const signResult = result.result;
await contract.methods.setPermit(signer, value, signResult)
.send({ from: signer });
const response = await contract.methods.get().call();
this.setState({ storageValue: response });
});
};
我已经将合约部署到 Rinkeby (0x729352f7541F205226234e3B8C4ABB820c68B380),但每次我尝试使用 setPermit 函数时,我都会在 Metamask 中收到“此交易预计会失败”错误。进一步调查显示,交易fails。我该如何解决这个问题?
经常检查你的数据类型:)