编译器
0.8.21+commit.d9974bed
文件 1 的 3:IERC20.sol
pragma solidity 0.8.21;
interface IERC20 {
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function transfer(address recipient, uint256 amount) external returns (bool);
}
文件 2 的 3:MerkleProof.sol
pragma solidity 0.8.21;
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 - 1 != totalHashes) {
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 - 1 != totalHashes) {
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)
}
}
}
文件 3 的 3:XccelerateStaking.sol
pragma solidity 0.8.21;
import "./MerkleProof.sol";
import "./IERC20.sol";
contract XccelerateStaking {
IERC20 public XLRT = IERC20(0x8a3C710E41cD95799C535f22DBaE371D7C858651);
address public owner;
address public rootFeeder;
bytes32 public merkleRoot;
mapping(bytes32 => bool) private _leafClaimed;
uint256 public totalStaked;
mapping(address => uint256) public staked;
event MerkleUpdated();
event Staked(address staker, uint256 amount, uint256 timestamp);
event Unstaked(address staker, uint256 amount, uint256 timestamp);
event Claimed(address staker, uint256 amount, uint256 timestamp);
modifier onlyOwner() {
require(owner == msg.sender, "Only the owner can call this function.");
_;
}
constructor() {
owner = msg.sender;
}
function setRootFeeder(address feeder) external onlyOwner {
rootFeeder = feeder;
}
function setMerkleRoot(bytes32 _merkleRoot) external payable {
require(msg.sender == rootFeeder, "Only the rootFeeder can call this function.");
merkleRoot = _merkleRoot;
emit MerkleUpdated();
}
function getLeaf(uint256 cumulativeReward) external view returns(bytes32) {
bytes32 leaf = keccak256(abi.encodePacked(msg.sender, cumulativeReward));
return leaf;
}
function verifyMerkleProof(bytes32[] calldata proof, address elementToProve, uint256 cumulativeReward) public view returns (bool) {
bytes32 leaf = keccak256(abi.encodePacked(elementToProve, cumulativeReward));
bool verified = MerkleProof.verify(proof, merkleRoot, leaf);
return verified;
}
function _claim(uint256 cumulativeReward, bytes32[] memory proof) private {
bytes32 leaf = keccak256(abi.encodePacked(msg.sender, cumulativeReward));
require(!_leafClaimed[leaf], "You have already claimed your rewards, wait until the next merkleRoot set.");
require(MerkleProof.verify(proof, merkleRoot, leaf), "Invalid proof");
_leafClaimed[leaf] = true;
payable(msg.sender).transfer(cumulativeReward);
}
function stake(uint256 amount) external {
require(amount > 0, "Cannot stake 0");
XLRT.transferFrom(msg.sender, address(this), amount);
staked[msg.sender] += amount;
totalStaked += amount;
emit Staked(msg.sender, amount, block.timestamp);
}
function unstake(uint256 amount, uint256 cumulativeReward, bytes32[] memory proof) external {
require(amount > 0, "Cannot unstake 0");
require(staked[msg.sender] >= amount, "unstake amount exceeds staked balance");
staked[msg.sender] -= amount;
totalStaked -= amount;
XLRT.transfer(msg.sender, amount);
if (cumulativeReward > 0)
_claim(cumulativeReward, proof);
emit Unstaked(msg.sender, amount, block.timestamp);
}
function claim(uint256 cumulativeReward, bytes32[] memory proof) external {
_claim(cumulativeReward, proof);
emit Claimed(msg.sender, cumulativeReward, block.timestamp);
}
function emergencyWithdraw() external onlyOwner{
payable(msg.sender).transfer(address(this).balance);
}
}
{
"compilationTarget": {
"XccelerateStaking.sol": "XccelerateStaking"
},
"evmVersion": "shanghai",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[],"name":"MerkleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Unstaked","type":"event"},{"inputs":[],"name":"XLRT","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cumulativeReward","type":"uint256"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"cumulativeReward","type":"uint256"}],"name":"getLeaf","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"merkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rootFeeder","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"name":"setMerkleRoot","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"feeder","type":"address"}],"name":"setRootFeeder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"staked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStaked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"cumulativeReward","type":"uint256"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"address","name":"elementToProve","type":"address"},{"internalType":"uint256","name":"cumulativeReward","type":"uint256"}],"name":"verifyMerkleProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]