Skip to content

Commit 8cb9e98

Browse files
committed
Fix:Testing Part
1 parent cd28886 commit 8cb9e98

16 files changed

+371
-23
lines changed

.gitmodules

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,9 @@
44
[submodule "lib/openzeppelin-contracts"]
55
path = lib/openzeppelin-contracts
66
url = https://github.com/openzeppelin/openzeppelin-contracts
7+
[submodule "lib/murky"]
8+
path = lib/murky
9+
url = https://github.com/dmfxyz/murky
10+
[submodule "lib/foundry-devops"]
11+
path = lib/foundry-devops
12+
url = https://github.com/chainaccelorg/foundry-devops

foundry.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22
src = "src"
33
out = "out"
44
libs = ["lib"]
5+
fs_permissions = [{ access = "read-write", path = "./" }]
56
remappings=[
6-
'@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/'
7+
'@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/',
8+
'foundry-devops/=lib/foundry-devops',
9+
'murky/=lib/murky/',
710
]
811

912
# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options

lib/forge-std

lib/foundry-devops

Submodule foundry-devops added at efff097

lib/murky

Submodule murky added at 5feccd1

script/DeployMerkleAirdrop.s.sol

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.24;
3+
4+
import {MerkleAirdrop, IERC20} from "../src/MerkleAirdrop.sol";
5+
import {Script} from "forge-std/Script.sol";
6+
import {BagelToken} from "../src/BagelToken.sol";
7+
import {console} from "forge-std/console.sol";
8+
9+
contract DeployMerkleAirdrop is Script {
10+
bytes32 public ROOT = 0xaa5d581231e596618465a56aa0f5870ba6e20785fe436d5bfb82b08662ccc7c4;
11+
uint256 public AMOUNT_TO_TRANSFER = 4 * (25 * 1e18);
12+
13+
function deployMerkleAirdrop() public returns (MerkleAirdrop, BagelToken) {
14+
vm.startBroadcast();
15+
BagelToken bagelToken = new BagelToken();
16+
MerkleAirdrop airdrop = new MerkleAirdrop(ROOT, IERC20(bagelToken));
17+
bagelToken.mint(bagelToken.owner(), AMOUNT_TO_TRANSFER);
18+
IERC20(bagelToken).transfer(address(airdrop), AMOUNT_TO_TRANSFER);
19+
vm.stopBroadcast();
20+
return (airdrop, bagelToken);
21+
}
22+
23+
function run() external returns (MerkleAirdrop, BagelToken) {
24+
return deployMerkleAirdrop();
25+
}
26+
}

script/GenerateInput.s.sol

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.24;
3+
4+
import {Script} from "forge-std/Script.sol";
5+
import {stdJson} from "forge-std/StdJson.sol";
6+
import {console} from "forge-std/console.sol";
7+
8+
contract GenerateInput is Script {
9+
uint256 private constant AMOUNT = 25 * 1e18;
10+
string[] types = new string[](2);
11+
uint256 count;
12+
string[] whitelist = new string[](4);
13+
string private constant INPUT_PATH = "/script/target/input.json";
14+
15+
function run() public {
16+
types[0] = "address";
17+
types[1] = "uint";
18+
whitelist[0] = "0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D";
19+
whitelist[1] = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266";
20+
whitelist[2] = "0x2ea3970Ed82D5b30be821FAAD4a731D35964F7dd";
21+
whitelist[3] = "0xf6dBa02C01AF48Cf926579F77C9f874Ca640D91D";
22+
count = whitelist.length;
23+
string memory input = _createJSON();
24+
vm.writeFile(string.concat(vm.projectRoot(), INPUT_PATH), input);
25+
26+
console.log("DONE: The output is found at %s", INPUT_PATH);
27+
}
28+
29+
function _createJSON() internal view returns (string memory) {
30+
string memory countString = vm.toString(count);
31+
string memory amountString = vm.toString(AMOUNT);
32+
string memory json = string.concat('{ "types": ["address", "uint"], "count":', countString, ',"values": {');
33+
for (uint256 i = 0; i < whitelist.length; i++) {
34+
if (i == whitelist.length - 1) {
35+
json = string.concat(
36+
json,
37+
'"',
38+
vm.toString(i),
39+
'"',
40+
': { "0":',
41+
'"',
42+
whitelist[i],
43+
'"',
44+
', "1":',
45+
'"',
46+
amountString,
47+
'"',
48+
" }"
49+
);
50+
} else {
51+
json = string.concat(
52+
json,
53+
'"',
54+
vm.toString(i),
55+
'"',
56+
': { "0":',
57+
'"',
58+
whitelist[i],
59+
'"',
60+
', "1":',
61+
'"',
62+
amountString,
63+
'"',
64+
" },"
65+
);
66+
}
67+
}
68+
json = string.concat(json, "} }");
69+
70+
return json;
71+
}
72+
}

script/Interact.s.sol

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.24;
3+
4+
import {Script, console} from "forge-std/Script.sol";
5+
import {DevOpsTools} from "foundry-devops/src/DevOpsTools.sol";
6+
import {MerkleAirdrop} from "../src/MerkleAirdrop.sol";
7+
8+
contract ClaimAirdrop is Script {
9+
address private constant CLAIMING_ADDRESS = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;
10+
uint256 private constant AMOUNT_TO_COLLECT = (25 * 1e18);
11+
12+
bytes32 private constant PROOF_ONE = 0xd1445c931158119b00449ffcac3c947d028c0c359c34a6646d95962b3b55c6ad;
13+
bytes32 private constant PROOF_TWO = 0xe5ebd1e1b5a5478a944ecab36a9a954ac3b6b8216875f6524caa7a1d87096576;
14+
bytes32[] private proof = [PROOF_ONE, PROOF_TWO];
15+
bytes private SIGNATURE =
16+
hex"fbd2270e6f23fb5fe9248480c0f4be8a4e9bd77c3ad0b1333cc60b5debc511602a2a06c24085d8d7c038bad84edc53664c8ce0346caeaa3570afec0e61144dc11c";
17+
18+
error ClaimAirdropScript__InvalidSignatureLength();
19+
20+
function claimAirdrop(address airdrop) public {
21+
vm.startBroadcast();
22+
(uint8 v, bytes32 r, bytes32 s) = splitSignature(SIGNATURE);
23+
console.log("Claiming Airdrop");
24+
MerkleAirdrop(airdrop).claim(CLAIMING_ADDRESS, AMOUNT_TO_COLLECT, proof, v, r, s);
25+
vm.stopBroadcast();
26+
console.log("Claimed Airdrop");
27+
}
28+
29+
function splitSignature(bytes memory sig) public pure returns (uint8 v, bytes32 r, bytes32 s) {
30+
if (sig.length != 65) {
31+
revert ClaimAirdropScript__InvalidSignatureLength();
32+
}
33+
assembly {
34+
r := mload(add(sig, 32))
35+
s := mload(add(sig, 64))
36+
v := byte(0, mload(add(sig, 96)))
37+
}
38+
}
39+
40+
function run() external {
41+
address mostRecentlyDeployed = DevOpsTools.get_most_recent_deployment("MerkleAirdrop", block.chainid);
42+
claimAirdrop(mostRecentlyDeployed);
43+
}
44+
}

script/MakeMerkle.s.sol

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.24;
3+
4+
import {Script} from "forge-std/Script.sol";
5+
import {stdJson} from "forge-std/StdJson.sol";
6+
import {console} from "forge-std/console.sol";
7+
import {Merkle} from "murky/src/Merkle.sol";
8+
import {ScriptHelper} from "murky/script/common/ScriptHelper.sol";
9+
10+
contract MakeMerkle is Script, ScriptHelper {
11+
using stdJson for string;
12+
13+
Merkle private m = new Merkle();
14+
15+
string private inputPath = "/script/target/input.json";
16+
string private outputPath = "/script/target/output.json";
17+
18+
string private elements = vm.readFile(string.concat(vm.projectRoot(), inputPath));
19+
string[] private types = elements.readStringArray(".types");
20+
uint256 private count = elements.readUint(".count");
21+
bytes32[] private leafs = new bytes32[](count);
22+
23+
string[] private inputs = new string[](count);
24+
string[] private outputs = new string[](count);
25+
26+
string private output;
27+
28+
function getValuesByIndex(uint256 i, uint256 j) internal pure returns (string memory) {
29+
return string.concat(".values.", vm.toString(i), ".", vm.toString(j));
30+
}
31+
32+
function generateJsonEntries(string memory _inputs, string memory _proof, string memory _root, string memory _leaf)
33+
internal
34+
pure
35+
returns (string memory)
36+
{
37+
string memory result = string.concat(
38+
"{",
39+
"\"inputs\":",
40+
_inputs,
41+
",",
42+
"\"proof\":",
43+
_proof,
44+
",",
45+
"\"root\":\"",
46+
_root,
47+
"\",",
48+
"\"leaf\":\"",
49+
_leaf,
50+
"\"",
51+
"}"
52+
);
53+
54+
return result;
55+
}
56+
57+
function run() public {
58+
console.log("Generating Merkle Proof for %s", inputPath);
59+
60+
for (uint256 i = 0; i < count; ++i) {
61+
string[] memory input = new string[](types.length);
62+
bytes32[] memory data = new bytes32[](types.length);
63+
64+
for (uint256 j = 0; j < types.length; ++j) {
65+
if (compareStrings(types[j], "address")) {
66+
address value = elements.readAddress(getValuesByIndex(i, j));
67+
data[j] = bytes32(uint256(uint160(value)));
68+
input[j] = vm.toString(value);
69+
} else if (compareStrings(types[j], "uint")) {
70+
uint256 value = vm.parseUint(elements.readString(getValuesByIndex(i, j)));
71+
data[j] = bytes32(value);
72+
input[j] = vm.toString(value);
73+
}
74+
}
75+
leafs[i] = keccak256(bytes.concat(keccak256(ltrim64(abi.encode(data)))));
76+
inputs[i] = stringArrayToString(input);
77+
}
78+
79+
for (uint256 i = 0; i < count; ++i) {
80+
string memory proof = bytes32ArrayToString(m.getProof(leafs, i));
81+
string memory root = vm.toString(m.getRoot(leafs));
82+
string memory leaf = vm.toString(leafs[i]);
83+
string memory input = inputs[i];
84+
outputs[i] = generateJsonEntries(input, proof, root, leaf);
85+
}
86+
output = stringArrayToArrayString(outputs);
87+
vm.writeFile(string.concat(vm.projectRoot(), outputPath), output);
88+
89+
console.log("DONE: The output is found at %s", outputPath);
90+
}
91+
}

script/SplitSignature.s.sol

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.24;
3+
4+
import {Script, console} from "forge-std/Script.sol";
5+
6+
contract SplitSignature is Script {
7+
error __SplitSignatureScript__InvalidSignatureLength();
8+
9+
function splitSignature(bytes memory sig) internal pure returns (uint8 v, bytes32 r, bytes32 s) {
10+
if (sig.length != 65) {
11+
revert __SplitSignatureScript__InvalidSignatureLength();
12+
}
13+
14+
assembly {
15+
r := mload(add(sig, 32))
16+
s := mload(add(sig, 64))
17+
v := byte(0, mload(add(sig, 96)))
18+
}
19+
}
20+
21+
function run() external view {
22+
string memory sig = vm.readFile("signature.txt");
23+
bytes memory sigBytes = vm.parseBytes(sig);
24+
(uint8 v, bytes32 r, bytes32 s) = splitSignature(sigBytes);
25+
console.log("v value:");
26+
console.log(v);
27+
console.log("r value:");
28+
console.logBytes32(r);
29+
console.log("s value:");
30+
console.logBytes32(s);
31+
}
32+
}

0 commit comments

Comments
 (0)