Skip to content

Commit 5e8fa18

Browse files
yingjingyangjolycao
and
jolycao
authored
fix readme && add contract for EIP712 (#314)
* add test code for EIP712 * fix contract * fix conflict * fix readme Co-authored-by: jolycao <[email protected]>
1 parent e6481ab commit 5e8fa18

File tree

14 files changed

+500
-21
lines changed

14 files changed

+500
-21
lines changed

basic/23-erc865-and-erc875/README.md

+37-16
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,30 @@
11
## 概要
2+
本样例主要介绍 ERC865, ERC875, EIP712 这三个合约功能及基本使用.
3+
24
### ERC865
3-
通过 test_DToken.js 介绍了如何使用“无Gas”交易,阐明了“无Gas”实际上意味着将Gas成本转移给其他人。
4-
使用此模式有很多好处,因此,它被广泛使用. 签名允许将交易 gas 成本从用户转移到服务提供商, 从而在许多情况下消除了相当大的障碍. 它还允许实现更高级的委派模式, 通常会对UX进行相当大的改进
5+
要在以太坊区块链上执行任何交易, 您必须付费. 该费用将支付给矿工用于采矿交易, 将其放入区块并保护区块链.
6+
此费用以Gas(气体限额* Gas​​价格)计算, 并以 ETH 支付.
7+
这给新用户带来了一些摩擦:
8+
```js
9+
1. 新用户必须了解以太坊的工作原理才能了解 gas 气价格和 gas 成本
10+
2. 他们必须获得必要的 ETH 以支付天然气
11+
```
12+
这两点为采用内置令牌的DAPPS创造了不必要的障碍, 为此提出了 ERC865 标准.
13+
介绍了一个中间人第三方, 该第三方愿意以代币收取转移费, 并将以必要的费用将转移交易以太币转发给区块链. 使用加密签名可以保护此过程.
14+
- 测试脚本介绍
15+
test-ERC865.js 介绍了如何使用“无Gas”交易, 阐明了“无Gas”实际上意味着将Gas成本转移给其他人.
16+
使用此模式有很多好处, 因此, 它被广泛使用. 签名允许将交易 gas 成本从用户转移到服务提供商, 从而在许多情况下消除了相当大的障碍. 它还允许实现更高级的委派模式, 通常会对UX进行相当大的改进
517

618
### ERC875
7-
支持原子交易的token
8-
9-
### EIP712 (todo)
10-
通过签名功能函数的好处是用户可以免费完成委托或投票交易, 同时会有可信的第三方花费gas费用将投票结果写到区块链中. 在本次教程中,我们重点展示这类函数的例子.
19+
ERC875 和 ERC721 一样, 是非同质代币, 但具有不同的接口.
20+
ERC875 与 ERC721 有两个最大的不同之处:
21+
- 一次买卖中, ERC875 只需要一次交易, 因此只需要支付一次 gas.(通过magiclink的方式,实现了原子交易)
22+
- 多个代币可以在一次交易中进行买卖.(比如卖家需要10张票打包销售)
23+
1124

25+
### EIP712
26+
EIP-712是一种更高级, 更安全的交易签名方法. 使用该标准不仅可以签署交易并且可以验证签名,而且可以将数据与签名一起传递到智能合约中,并且可以根据该数据验证签名以了解签名者是否是实际发送该签名的人要在交易中调用的数据.
27+
EIP-712提出了数据的标准结构和从结构化消息生成散列的定义过程, 然后使用此散列生成签名. 通过这种方式, 为发送交易生成的签名与为验证身份或任何其他目的生成的签名之间就有了明显的区别.
1228

1329
### ERC777 (todo)
1430

@@ -23,17 +39,22 @@ https://eips.ethereum.org/EIPS/eip-2929
2339
yarn
2440
```
2541

26-
- 测试代理合约
42+
- 测试 ERC865 合约
43+
```
44+
npx hardhat test test/test-ERC865.js
45+
```
46+
47+
- 测试 EIP712 合约
2748
```
28-
npx hardhat test test/test_DToken.js
49+
npx hardhat test test/test-EIP712.js
2950
```
3051

3152
## 参考链接
32-
https://github.com/propsproject/props-token-distribution
33-
https://learnblockchain.cn/article/1357
34-
https://learnblockchain.cn/2019/04/24/token-EIP712
35-
https://learnblockchain.cn/article/1496
36-
https://medium.com/alphawallet/erc875-a-new-standard-for-non-fungible-tokens-and-cheap-atomic-swaps-93ab85b9e7f9
37-
https://github.com/AlphaWallet/ERC875-Example-Implementation
38-
https://github.com/ethereum/EIPs/tree/master/assets
39-
EIP712知乎:https://www.zhihu.com/people/wang-da-chui-82-1/posts
53+
Props Token Contracts: https://github.com/propsproject/props-token-distribution
54+
Metamask按照EIP-712规范签名完成委托和投票: https://learnblockchain.cn/article/1357
55+
为 DApp 编写 EIP712 签名: https://learnblockchain.cn/2019/04/24/token-EIP712
56+
链下 EIP2612 签名: https://learnblockchain.cn/article/1496
57+
ERC875: https://medium.com/alphawallet/erc875-a-new-standard-for-non-fungible-tokens-and-cheap-atomic-swaps-93ab85b9e7f9
58+
ERC875-Example: https://github.com/AlphaWallet/ERC875-Example-Implementation
59+
EIP 库: https://github.com/ethereum/EIPs/tree/master/assets
60+
EIP712知乎:https://www.zhihu.com/people/wang-da-chui-82-1/posts
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
pragma solidity ^0.4.24;
2+
3+
contract EIP712 {
4+
5+
struct EIP712Domain {
6+
string name;
7+
string version;
8+
uint256 chainId;
9+
address verifyingContract;
10+
}
11+
12+
struct Person {
13+
string name;
14+
address wallet;
15+
}
16+
17+
struct Mail {
18+
Person from;
19+
Person to;
20+
string contents;
21+
}
22+
23+
bytes32 constant EIP712DOMAIN_TYPEHASH = keccak256(
24+
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
25+
);
26+
27+
bytes32 constant PERSON_TYPEHASH = keccak256(
28+
"Person(string name,address wallet)"
29+
);
30+
31+
bytes32 constant MAIL_TYPEHASH = keccak256(
32+
"Mail(Person from,Person to,string contents)Person(string name,address wallet)"
33+
);
34+
35+
bytes32 DOMAIN_SEPARATOR;
36+
37+
mapping(address => Person) public froms;
38+
39+
mapping(address => Person) public tos;
40+
41+
mapping(address => string) public contents;
42+
43+
constructor () public {
44+
DOMAIN_SEPARATOR = hash(EIP712Domain({
45+
name: "Ether Mail",
46+
version: '1',
47+
chainId: 1,
48+
// verifyingContract: this
49+
verifyingContract: 0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC
50+
}));
51+
}
52+
53+
function setFrom( address _target, string _name, address _wallet) public {
54+
froms[_target] = Person({
55+
name: _name,
56+
wallet: _wallet
57+
});
58+
}
59+
60+
function setTo( address _target, string _name, address _wallet) public {
61+
tos[_target] = Person({
62+
name: _name,
63+
wallet: _wallet
64+
});
65+
}
66+
67+
function setContent( address _target, string _content) public {
68+
contents[_target] = _content;
69+
}
70+
71+
function hash(EIP712Domain eip712Domain) internal pure returns (bytes32) {
72+
return keccak256(abi.encode(
73+
EIP712DOMAIN_TYPEHASH,
74+
keccak256(bytes(eip712Domain.name)),
75+
keccak256(bytes(eip712Domain.version)),
76+
eip712Domain.chainId,
77+
eip712Domain.verifyingContract
78+
));
79+
}
80+
81+
function hash(Person person) internal pure returns (bytes32) {
82+
return keccak256(abi.encode(
83+
PERSON_TYPEHASH,
84+
keccak256(bytes(person.name)),
85+
person.wallet
86+
));
87+
}
88+
89+
function hash(Mail mail) internal pure returns (bytes32) {
90+
return keccak256(abi.encode(
91+
MAIL_TYPEHASH,
92+
hash(mail.from),
93+
hash(mail.to),
94+
keccak256(bytes(mail.contents))
95+
));
96+
}
97+
98+
function verify(address _target, uint8 v, bytes32 r, bytes32 s) public view returns (bool) {
99+
Mail memory mail = Mail({
100+
from: froms[_target],
101+
to: tos[_target],
102+
contents: contents[_target]
103+
});
104+
// Note: we need to use `encodePacked` here instead of `encode`.
105+
bytes32 digest = keccak256(abi.encodePacked(
106+
"\x19\x01",
107+
DOMAIN_SEPARATOR,
108+
hash(mail)
109+
));
110+
return ecrecover(digest, v, r, s) == _target;
111+
}
112+
113+
/* function test() public view returns (bool) {
114+
// Example signed message
115+
Mail memory mail = Mail({
116+
from: Person({
117+
name: "Cow",
118+
wallet: 0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826
119+
}),
120+
to: Person({
121+
name: "Bob",
122+
wallet: 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB
123+
}),
124+
contents: "Hello, Bob!"
125+
});
126+
uint8 v = 28;
127+
bytes32 r = 0x4355c47d63924e8a72e509b65029052eb6c299d53a04e167c5775fd466751c9d;
128+
bytes32 s = 0x07299936d304c153f6443dfa05f40ff007d72911b6f72307f996231605b91562;
129+
130+
assert(DOMAIN_SEPARATOR == 0xf2cee375fa42b42143804025fc449deafd50cc031ca257e0b194a650a912090f);
131+
assert(hash(mail) == 0xc52c0ee5d84264471806290a3f2c4cecfc5490626bf912d01f240d7a274b371e);
132+
assert(verify(mail, v, r, s));
133+
return true;
134+
} */
135+
}

basic/23-erc865-and-erc875/contracts/erc875/ERC875Token.sol

+17-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ pragma solidity ^0.4.25;
22

33
import "./IERC875.sol";
44

5-
contract ERC875Token is ERC875 {
5+
contract ERC875Token is IERC875 {
66
uint totalTickets;
77
mapping(address => uint256[]) inventory;
88
uint16 ticketIndex = 0; //to track mapping in tickets
@@ -77,6 +77,17 @@ contract ERC875Token is ERC875 {
7777
seller.transfer(msg.value);
7878
}
7979

80+
function verify(uint256 expiry,
81+
uint256[] tokenIndices,
82+
uint8 v,
83+
bytes32 r,
84+
bytes32 s) public payable
85+
{
86+
bytes12 prefix = "ERC800-CNID1";
87+
bytes32 message = encodeMessage(prefix, msg.value, expiry, tokenIndices);
88+
address seller = ecrecover(message, v, r, s);
89+
}
90+
8091

8192
//must also sign in the contractAddress
8293
//prefix must contain ERC and chain id
@@ -132,6 +143,11 @@ contract ERC875Token is ERC875 {
132143
return numOfTransfers;
133144
}
134145

146+
function supportsInterface(bytes4 interfaceID) external view returns (bool)
147+
{
148+
return false;
149+
}
150+
135151
function isContractExpired() public view returns (bool)
136152
{
137153
if(block.timestamp > expiryTimeStamp)

basic/23-erc865-and-erc875/contracts/erc875/IERC165.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
pragma solidity ^0.4.24;
22

3-
contract ERC165 {
3+
contract IERC165 {
44
/// @notice Query if a contract implements an interface
55
/// @param interfaceID The interface identifier, as specified in ERC-165
66
/// @dev Interface identification is specified in ERC-165. This function

basic/23-erc865-and-erc875/contracts/erc875/IERC875.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ pragma solidity ^0.4.25;
22

33
import "./IERC165.sol";
44

5-
contract ERC875 is ERC165 {
5+
contract IERC875 is IERC165 {
66
event Transfer(address indexed _from, address indexed _to, uint256[] tokenIndices);
77

88
function name() constant public returns (string name);

basic/23-erc865-and-erc875/package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
"hardhat": "^2.3.3"
1515
},
1616
"dependencies": {
17-
"dotenv": "^10.0.0"
17+
"dotenv": "^10.0.0",
18+
"ethereumjs-abi": "^0.6.8",
19+
"ethers-eip712": "^0.2.0"
1820
}
1921
}

0 commit comments

Comments
 (0)