Skip to content

Commit bbd8e21

Browse files
committed
fix readme
1 parent 46fe41f commit bbd8e21

File tree

6 files changed

+121
-70
lines changed

6 files changed

+121
-70
lines changed

basic/42-merkle-distributor-airdrop/README.md

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -113,40 +113,61 @@ npx hardhat test
113113
cp .env.exmpale .env
114114

115115
## 在 .env 文件中配置 PRIVATE_KEY, INFURA_ID, PROJECT_ID, TARGET_ACCOUNT
116-
## 其中 TARGET_ACCOUNT 为可以领取红包的账户地址
116+
## 比如有一个账户 A , 那么 PRIVATE_KEY 为账户 A 对应的 PRIVATE_KEY, TARGET_ACCOUNT 为账户 A 对应的账户地址
117117
```
118118

119+
- 配置 redpacketAddressList
120+
因为红包领取时会进行 Merkle 校验, 所以需要在 Merkle List 中配置对应的账户地址.
121+
修改 scripts/redpacket/redpacketAddressList.json 文件,在其中加入上一步操作中 "TARGET_ACCOUNT" 的值.
122+
119123
- 安装依赖
120124
```shell
121125
yarn
122126
```
123127

124128
- 部署 ERC20 合约
129+
执行如下命令,然后获取输出的 "Token address" 值
125130
```shell
126-
npx hardhat run scripts/redpacket/1-deploySimpleToken --network kovan
131+
npx hardhat run scripts/redpacket/1-deploySimpleToken.js --network kovan
132+
133+
## 输入信息如下:
134+
Deploying contracts with the account: 0x3238f24e7C752398872B768Ace7dd63c54CfEFEc
135+
Account balance: 796474026501725149
136+
Token address: 0xdc6999dC3f818B4f74550569CCC7C82091cA419F
137+
1000000000
127138
```
128139

129140
- 部署 RedPacket 合约
141+
执行如下命令,然后获取输出的 "RedPacket address" 值
130142
```shell
131-
npx hardhat run scripts/redpacket/2-deployHappyRedPacket --network kovan
143+
npx hardhat run scripts/redpacket/2-deployHappyRedPacket.js --network kovan
144+
145+
## 输出信息如下:
146+
Deploying contracts with the account: 0x3238f24e7C752398872B768Ace7dd63c54CfEFEc
147+
Account balance: 783625061469463255
148+
RedPacket address: 0x6F35e57a7421F5b04DDb47b67453A5a5Be32e58B
132149
```
133150

134-
- 创建 红包
135-
修改 scripts/redpacket/3-createRedPacket 文件中的 "HappyRedPacketAddress" 和 "SimpleTokenAddress" 地址为上面输出的地址, 然后执行下面的命令
151+
- 创建红包
152+
修改 scripts/redpacket/3-createRedPacket.js 文件中的 "HappyRedPacketAddress" 和 "SimpleTokenAddress" 地址为上面输出的地址, 然后执行下面的命令, 获取输出的 "RedpacketId"
136153
```shell
137-
npx hardhat run scripts/redpacket/3-createRedPacket --network kovan
154+
npx hardhat run scripts/redpacket/3-createRedPacket.js --network kovan
155+
156+
## 输出值
157+
Approve Successfully
158+
merkleTree Root: 0x5cc6f1ff34a2c6f871d40cdc4559468f96a7ec06d7bf6ab0f9b5aeccc9b33154
159+
CreationSuccess Event, total: 10000 RedpacketId: 0x45eb11e56a1b699f5e99bd16785c84b73a8257c712e0d1f31306ab1e3423b2e0
160+
Create Red Packet successfully
138161
```
139162

140-
- 进行签名
163+
- 领取红包
164+
修改 "4-claimRedpacket.js" 文件中的 "HappyRedPacketAddress" 和 "redpacketID" 值为上面的输出值, 然后执行下面的命令进行红包的 claim
141165
```shell
142-
npx hardhat run scripts/redpacket/4-signMessage
166+
npx hardhat run scripts/redpacket/4-claimRedpacket.js --network kovan
143167

144168
## 得到的输出 "Sign Message:" 即为领取红包时需要输入的签名信息,防止恶意领取
145169
```
146170

147-
- 领取红包
148-
在 Etherscan 上验证合约后,即可通过 Etherscan 调用 claim 方法进行领取
149-
150171
## 参考链接
151172

152173
- https://github.com/Anish-Agnihotri/merkle-airdrop-starter

basic/42-merkle-distributor-airdrop/contracts/redpacket/HappyRedPacket.sol

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,15 @@ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
1414
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
1515
import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
1616
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
17+
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
1718

1819
contract HappyRedPacket is Initializable {
1920
using SafeMath for uint256;
2021

2122
struct RedPacket {
2223
Packed packed;
2324
mapping(address => uint256) claimed_list;
24-
address public_key;
25+
bytes32 merkleroot;
2526
address creator;
2627
}
2728

@@ -68,7 +69,7 @@ contract HappyRedPacket is Initializable {
6869

6970
// Inits a red packet instance
7071
// _token_type: 0 - ETH 1 - ERC20
71-
function create_red_packet (address _public_key, uint _number, bool _ifrandom, uint _duration,
72+
function create_red_packet (bytes32 _merkleroot, uint _number, bool _ifrandom, uint _duration,
7273
bytes32 _seed, string memory _message, string memory _name,
7374
uint _token_type, address _token_addr, uint _total_tokens)
7475
public payable {
@@ -97,7 +98,7 @@ contract HappyRedPacket is Initializable {
9798
RedPacket storage redp = redpacket_by_id[_id];
9899
redp.packed.packed1 = wrap1(received_amount, _duration);
99100
redp.packed.packed2 = wrap2(_token_addr, _number, _token_type, _random_type);
100-
redp.public_key = _public_key;
101+
redp.merkleroot = _merkleroot;
101102
redp.creator = msg.sender;
102103
}
103104
{
@@ -110,7 +111,7 @@ contract HappyRedPacket is Initializable {
110111
}
111112

112113
// It takes the signed msg.sender message as verification passcode
113-
function claim(bytes32 id, bytes memory signedMsg, address payable recipient)
114+
function claim(bytes32 id, bytes32[] memory proof, address payable recipient)
114115
public returns (uint claimed) {
115116

116117
RedPacket storage rp = redpacket_by_id[id];
@@ -121,8 +122,8 @@ contract HappyRedPacket is Initializable {
121122
uint claimed_number = unbox(packed.packed2, 224, 15);
122123
require (claimed_number < total_number, "Out of stock");
123124

124-
address public_key = rp.public_key;
125-
require(_verify(signedMsg, public_key), "Verification failed");
125+
bytes32 merkleroot = rp.merkleroot;
126+
require(MerkleProof.verify(proof, merkleroot, _leaf(msg.sender)), 'Verification failed');
126127

127128
uint256 claimed_tokens;
128129
uint256 token_type = unbox(packed.packed2, 254, 1);
@@ -159,14 +160,6 @@ contract HappyRedPacket is Initializable {
159160
return claimed_tokens;
160161
}
161162

162-
// as a workaround for "CompilerError: Stack too deep, try removing local variables"
163-
function _verify(bytes memory signedMsg, address public_key) private view returns (bool verified) {
164-
bytes memory prefix = "\x19Ethereum Signed Message:\n20";
165-
bytes32 prefixedHash = keccak256(abi.encodePacked(prefix, msg.sender));
166-
address calculated_public_key = ECDSA.recover(prefixedHash, signedMsg);
167-
return (calculated_public_key == public_key);
168-
}
169-
170163
// Returns 1. remaining value 2. total number of red packets 3. claimed number of red packets
171164
function check_availability(bytes32 id) external view returns ( address token_address, uint balance, uint total,
172165
uint claimed, bool expired, uint256 claimed_amount) {
@@ -182,6 +175,10 @@ contract HappyRedPacket is Initializable {
182175
);
183176
}
184177

178+
function _leaf(address account) internal pure returns (bytes32){
179+
return keccak256(abi.encodePacked(account));
180+
}
181+
185182
function refund(bytes32 id) public {
186183
RedPacket storage rp = redpacket_by_id[id];
187184
Packed memory packed = rp.packed;

basic/42-merkle-distributor-airdrop/scripts/redpacket/3-createRedPacket.js

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,19 @@
55
// Runtime Environment's members available in the global scope.
66
const { ethers } = require('hardhat');
77
require('dotenv').config();
8+
const { MerkleTree } = require('merkletreejs');
9+
const keccak256 = require('keccak256');
10+
const addresList = require('./redpacketAddressList.json');
11+
12+
function hashToken(account) {
13+
return Buffer.from(ethers.utils.solidityKeccak256(['address'], [account]).slice(2), 'hex')
14+
}
815

916
async function main() {
1017
const [deployer] = await ethers.getSigners();
11-
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY);
1218

13-
const HappyRedPacketAddress = "0x1337ee7C6969692c6153e5e0cEDC637560AC7E5f";
14-
const SimpleTokenAddress = "0x26aa59598210AE7613d5Bf3aCB01416fdaf6EBe7";
19+
const HappyRedPacketAddress = "0xE9c061465E9eaF01D1c8F9Dfc2487Db31a053bb0";
20+
const SimpleTokenAddress = "0xdc6999dC3f818B4f74550569CCC7C82091cA419F";
1521

1622
const redPacket = await ethers.getContractAt("HappyRedPacket", HappyRedPacketAddress, deployer);
1723
const simpleToken = await ethers.getContractAt("SimpleToken", SimpleTokenAddress, deployer);
@@ -20,11 +26,14 @@ async function main() {
2026
await tx.wait()
2127

2228
console.log("Approve Successfully");
23-
console.log("Public key is: ", wallet.address);
29+
30+
merkleTree = new MerkleTree(addresList.map(address => hashToken(address)), keccak256, { sortPairs: true });
31+
merkleTreeRoot = merkleTree.getHexRoot();
32+
console.log("merkleTree Root:",merkleTreeRoot);
2433

2534
// create_red_packet
2635
let creationParams = {
27-
public_key: wallet.address,
36+
merkleroot: merkleTreeRoot,
2837
number: 3,
2938
ifrandom: true,
3039
duration: 2**30,
@@ -38,7 +47,7 @@ async function main() {
3847

3948
redPacket.once('CreationSuccess', ( total, id, name, message, creator, creation_time, token_address, number, ifrandom, duration) => {
4049
console.log(
41-
`CreationSuccess Event, total: ${total} id: ${id} `
50+
`CreationSuccess Event, total: ${total} RedpacketId: ${id} `
4251
);
4352
});
4453

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// We require the Hardhat Runtime Environment explicitly here. This is optional
2+
// but useful for running the script in a standalone fashion through `node <script>`.
3+
//
4+
// When running the script with `hardhat run <script>` you'll find the Hardhat
5+
// Runtime Environment's members available in the global scope.
6+
const { ethers } = require('hardhat');
7+
require('dotenv').config();
8+
const { MerkleTree } = require('merkletreejs');
9+
const keccak256 = require('keccak256');
10+
const addresList = require('./redpacketAddressList.json');
11+
12+
function hashToken(account) {
13+
return Buffer.from(ethers.utils.solidityKeccak256(['address'], [account]).slice(2), 'hex')
14+
}
15+
16+
async function main() {
17+
const [deployer] = await ethers.getSigners();
18+
19+
const HappyRedPacketAddress = "0xE9c061465E9eaF01D1c8F9Dfc2487Db31a053bb0";
20+
const redPacket = await ethers.getContractAt("HappyRedPacket", HappyRedPacketAddress, deployer);
21+
const redpacketID = "0x45eb11e56a1b699f5e99bd16785c84b73a8257c712e0d1f31306ab1e3423b2e0"
22+
23+
merkleTree = new MerkleTree(addresList.map(address => hashToken(address)), keccak256, { sortPairs: true });
24+
let proof = merkleTree.getHexProof(hashToken(deployer.address));
25+
console.log("merkleTree proof: ",proof);
26+
27+
let createRedPacketRecipt = await redPacket.claim(redpacketID,proof,deployer.address);
28+
await createRedPacketRecipt.wait();
29+
30+
console.log("Claim Red Packet successfully");
31+
}
32+
33+
// We recommend this pattern to be able to use async/await everywhere
34+
// and properly handle errors.
35+
main()
36+
.then(() => process.exit(0))
37+
.catch((error) => {
38+
console.error(error);
39+
process.exit(1);
40+
});

basic/42-merkle-distributor-airdrop/scripts/redpacket/4-signMessage.js

Lines changed: 0 additions & 39 deletions
This file was deleted.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[
2+
"0xa111C225A0aFd5aD64221B1bc1D5d817e5D3Ca15",
3+
"0x8de806462823aD25056eE8104101F9367E208C14",
4+
"0x801EfbcFfc2Cf572D4C30De9CEE2a0AFeBfa1Ce1",
5+
"0x7DdC72Eb160F6A325A5927299b2715Abd0bEA55B",
6+
"0x5aB21736841D90fc48D6aA003A7791E62f52692f",
7+
"0x940Da56126BE133Ddaa53Fe0FE52B4F42d3f761F",
8+
"0x7De3e7f2821ef6310B353c00628D02B57ad661D8",
9+
"0x6B831bf30f30701D5595DedDA9873F9F93495FBb",
10+
"0x3EE9626735Bc3585D2B4b3B6F604769aB3450593",
11+
"0xb0874963aCcA3FD8C3740fC13A9948b89D34B19A",
12+
"0x4Ea6D5DF8291E973289C726b2a36836BF232C0D1",
13+
"0xa702766f94C9C515722251a8A9FE7Ea9141eE73B",
14+
"0x346229540D5849203f84A727636AE4Eb6eA265fD",
15+
"0x8Ee432c17f59e5989069B77164a68fbAAcF46A2B",
16+
"0xeAE26C61ab4fF2B8e0d38CE3C44b3D115cfB0FDE",
17+
"0x30e2326ee1bf319EFA6117E6E6C8Df334243E76d",
18+
"0xBcfF64A3f8EE87d8D82B8c9b6D35b150761b430D",
19+
"0x0EbDa2F020DA73192F6Ab99c31224b8b1Aa32df8",
20+
"0x0904b2214f21bdEc6f567469b57cc9444D4f4DdB",
21+
"0x7d33793CFdb315882cfF375096A4c0EF7d3fC0f0",
22+
"0x3238f24e7C752398872B768Ace7dd63c54CfEFEc"
23+
]

0 commit comments

Comments
 (0)