前言本文主要实现EIP721类型化数据签名的智能合约的开发、测试、部署、交互,测试过程:涉及到前端通过ethers库和合约以及钱包的交互;EIP712类型化数据签名定义:一种以太坊改进提案,旨在提供一种更高级、更安全的类型化数据签名方法;背景与重要性链下签名,链上验证:EIP712
本文主要实现EIP721类型化数据签名的智能合约的开发、测试、部署、交互,测试过程:涉及到前端通过ethers库和合约以及钱包的交互;
定义:一种以太坊改进提案,旨在提供一种更高级、更安全的类型化数据签名方法;
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import "hardhat/console.sol";
contract EIP712Storage is EIP712 {
bytes32 public constant PERMIT_TYPEHASH =
keccak256("Permit(address owner,uint256 value,uint256 nonce,uint256 deadline)");
mapping(address => uint256) public nonces;
uint256 private _value;
constructor() EIP712("EIP712Storage", "1.0.0") {}
function storeData(
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public {
require(block.timestamp <= deadline, "EIP712Storage: expired deadline");
bytes32 structHash = keccak256(
abi.encode(
PERMIT_TYPEHASH,
msg.sender,
value,
nonces[msg.sender]++,
deadline
));
bytes32 hash = _hashTypedDataV4(structHash);
address signer = ECDSA.recover(hash, v, r, s);
require(signer == msg.sender, "EIP712Storage: invalid signature");
_value = value;
}
function retrieve() public view returns (uint256) {
return _value;
}
function getDomainSeparator() public view returns (bytes32) {
return _domainSeparatorV4();
}
}
# 部署指令
# npx hardhat deploy
说明:主要测试签名有效、无效、时间过期三种情况的测试
const { ethers } = require("hardhat");
const { expect } = require("chai");
describe("EIP712Storage", function () {
let EIP712Storage;
let eip712Storage;
let owner;
let addr1;
let addr2;
beforeEach(async function () {
await deployments.fixture(["EIP712Storage"]);
[owner, addr1, addr2] = await ethers.getSigners();
const EIP712StorageFactory = await deployments.get("EIP712Storage");
eip712Storage = await ethers.getContractAt("EIP712Storage",EIP712StorageFactory.address);
//和上面是一样的都是部署合约
// const EIP712StorageFactory = await ethers.getContractFactory("EIP712Storage");
// eip712Storage = await EIP712StorageFactory.deploy();
// await eip712Storage.waitForDeployment();
});
describe("Storing with EIP712 signature", function () {
it("有效签名存储", async function () {
const chainId = (await ethers.provider.getNetwork()).chainId;
// 构建域分隔符
const domain = {
name: "EIP712Storage",
version: "1.0.0",
chainId: chainId,
verifyingContract: await eip712Storage.getAddress()
};
// 定义类型
const types = {
Permit: [
{ name: "owner", type: "address" },
{ name: "value", type: "uint256" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" }
]
};
const value = 42;
const deadline = Math.floor(Date.now() / 1000) + 60 * 60; // 1 hour from now
const nonce = await eip712Storage.nonces(owner.address);
// 准备签名数据
const message = {
owner: owner.address,
value: value,
nonce: nonce,
deadline: deadline
};
// 签名
const signature = await owner.signTypedData(domain, types, message);
const { v, r, s } = ethers.Signature.from(signature);
// 存储数据
await eip712Storage.storeData(value, deadline, v, r, s);
// 验证存储的值
expect(await eip712Storage.retrieve()).to.equal(value);
});
it("日期过期测试", async function () {
const chainId = (await ethers.provider.getNetwork()).chainId;
const domain = {
name: "EIP712Storage",
version: "1.0.0",
chainId: chainId,
verifyingContract: await eip712Storage.getAddress()
};
const types = {
Permit: [
{ name: "owner", type: "address" },
{ name: "value", type: "uint256" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" }
]
};
const value = 42;
const deadline = Math.floor(Date.now() / 1000) - 60; // 1 minute ago
const nonce = await eip712Storage.nonces(owner.address);
const message = {
owner: owner.address,
value: value,
nonce: nonce,
deadline: deadline
};
const signature = await owner.signTypedData(domain, types, message);
const { v, r, s } = ethers.Signature.from(signature);
await expect(
eip712Storage.storeData(value, deadline, v, r, s)
).to.be.revertedWith("EIP712Storage: expired deadline");
});
it("签名无效", async function () {
const chainId = (await ethers.provider.getNetwork()).chainId;
const domain = {
name: "EIP712Storage",
version: "1.0.0",
chainId: chainId,
verifyingContract: await eip712Storage.getAddress()
};
const types = {
Permit: [
{ name: "owner", type: "address" },
{ name: "value", type: "uint256" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" }
]
};
const value = 42;
const deadline = Math.floor(Date.now() / 1000) + 60 * 60;
const nonce = await eip712Storage.nonces(owner.address);
const message = {
owner: owner.address,
value: value,
nonce: nonce,
deadline: deadline
};
// 使用不同的签名者
const signature = await addr1.signTypedData(domain, types, message)
const { v, r, s } = ethers.Signature.from(signature);
await expect(
eip712Storage.connect(owner).storeData(value, deadline, v, r, s)
).to.be.revertedWith("EIP712Storage: invalid signature");
});
});
});
# 测试指令
# npx hardhat test ./test/xxx.js
module.exports = async function ({getNamedAccounts,deployments}) {
const firstAccount = (await getNamedAccounts()).firstAccount;
const {deploy,log} = deployments;
const EIP712Storage=await deploy("EIP712Storage",{
contract: "EIP712Storage",
from: firstAccount,
args: [],
log: true,
// waitConfirmations: 1,
})
console.log("EIP712Storage合约地址",EIP712Storage.address)
}
module.exports.tags = ["all", "EIP712Storage"]
# 部署指令
# npx hardhat deploy
以上就是EIP712 类型化数据签名合约的开发、测试、部署全部流程,主要包含了测试了签名有效,无效和时间过期三种情况。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!