编译器
0.8.24+commit.e11b9ed9
文件 1 的 3:CSEarlyAdoption.sol
pragma solidity 0.8.24;
import { MerkleProof } from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import { ICSEarlyAdoption } from "./interfaces/ICSEarlyAdoption.sol";
contract CSEarlyAdoption is ICSEarlyAdoption {
bytes32 public immutable TREE_ROOT;
uint256 public immutable CURVE_ID;
address public immutable MODULE;
mapping(address => bool) internal _consumedAddresses;
event Consumed(address indexed member);
error InvalidProof();
error AlreadyConsumed();
error InvalidTreeRoot();
error InvalidCurveId();
error ZeroModuleAddress();
error SenderIsNotModule();
constructor(bytes32 treeRoot, uint256 curveId, address module) {
if (treeRoot == bytes32(0)) revert InvalidTreeRoot();
if (curveId == 0) revert InvalidCurveId();
if (module == address(0)) revert ZeroModuleAddress();
TREE_ROOT = treeRoot;
CURVE_ID = curveId;
MODULE = module;
}
function consume(address member, bytes32[] calldata proof) external {
if (msg.sender != MODULE) revert SenderIsNotModule();
if (_consumedAddresses[member]) revert AlreadyConsumed();
if (!verifyProof(member, proof)) revert InvalidProof();
_consumedAddresses[member] = true;
emit Consumed(member);
}
function isConsumed(address member) external view returns (bool) {
return _consumedAddresses[member];
}
function verifyProof(
address member,
bytes32[] calldata proof
) public view returns (bool) {
return MerkleProof.verifyCalldata(proof, TREE_ROOT, hashLeaf(member));
}
function hashLeaf(address member) public pure returns (bytes32) {
return keccak256(bytes.concat(keccak256(abi.encode(member))));
}
}
文件 2 的 3:ICSEarlyAdoption.sol
pragma solidity 0.8.24;
interface ICSEarlyAdoption {
function CURVE_ID() external view returns (uint256);
function TREE_ROOT() external view returns (bytes32);
function verifyProof(
address addr,
bytes32[] calldata proof
) external view returns (bool);
function consume(address sender, bytes32[] calldata proof) external;
function isConsumed(address sender) external view returns (bool);
}
文件 3 的 3:MerkleProof.sol
pragma solidity ^0.8.20;
library MerkleProof {
error MerkleProofInvalidMultiproof();
function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
return processProof(proof, leaf) == root;
}
function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
return processProofCalldata(proof, leaf) == root;
}
function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
function multiProofVerify(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProof(proof, proofFlags, leaves) == root;
}
function multiProofVerifyCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProofCalldata(proof, proofFlags, leaves) == root;
}
function processMultiProof(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
uint256 leavesLen = leaves.length;
uint256 proofLen = proof.length;
uint256 totalHashes = proofFlags.length;
if (leavesLen + proofLen != totalHashes + 1) {
revert MerkleProofInvalidMultiproof();
}
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i]
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
: proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
if (proofPos != proofLen) {
revert MerkleProofInvalidMultiproof();
}
unchecked {
return hashes[totalHashes - 1];
}
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function processMultiProofCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
uint256 leavesLen = leaves.length;
uint256 proofLen = proof.length;
uint256 totalHashes = proofFlags.length;
if (leavesLen + proofLen != totalHashes + 1) {
revert MerkleProofInvalidMultiproof();
}
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i]
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
: proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
if (proofPos != proofLen) {
revert MerkleProofInvalidMultiproof();
}
unchecked {
return hashes[totalHashes - 1];
}
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
}
function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
assembly {
mstore(0x00, a)
mstore(0x20, b)
value := keccak256(0x00, 0x40)
}
}
}
{
"compilationTarget": {
"src/CSEarlyAdoption.sol": "CSEarlyAdoption"
},
"evmVersion": "cancun",
"libraries": {
"src/lib/AssetRecovererLib.sol:AssetRecovererLib": "0xa74528edc289b1a597faf83fcff7eff871cc01d9",
"src/lib/NOAddresses.sol:NOAddresses": "0xf8e5de8baf8ad7c93dcb61d13d00eb3d57131c72",
"src/lib/QueueLib.sol:QueueLib": "0xd19b40cb5401f1413d014a56529f03b3452f70f9"
},
"metadata": {
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 250
},
"remappings": [
":@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/",
":@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/",
":ds-test/=node_modules/ds-test/src/",
":forge-std/=node_modules/forge-std/src/"
]
}
[{"inputs":[{"internalType":"bytes32","name":"treeRoot","type":"bytes32"},{"internalType":"uint256","name":"curveId","type":"uint256"},{"internalType":"address","name":"module","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyConsumed","type":"error"},{"inputs":[],"name":"InvalidCurveId","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[],"name":"InvalidTreeRoot","type":"error"},{"inputs":[],"name":"SenderIsNotModule","type":"error"},{"inputs":[],"name":"ZeroModuleAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"member","type":"address"}],"name":"Consumed","type":"event"},{"inputs":[],"name":"CURVE_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MODULE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TREE_ROOT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"member","type":"address"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"consume","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"member","type":"address"}],"name":"hashLeaf","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"member","type":"address"}],"name":"isConsumed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"member","type":"address"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"verifyProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]