编译器
0.8.17+commit.8df45f5f
文件 1 的 5:BpxClaim.sol
import { ProxyOwnable } from "./utils/ProxyOwnable.sol";
import { MerkleProofLib } from "./utils/MerkleProofLib.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { Errors } from "./library/errors/Errors.sol";
pragma solidity >=0.8.4 <0.9.0;
contract BpxClaim is ProxyOwnable {
struct ClaimWindow {
IERC20 bpxContract;
uint48 startTime;
uint48 endTime;
}
event CurrencyClaimed(address indexed claimant, uint256 indexed amount, address indexed operator);
bytes32 public authRoot;
ClaimWindow private _claim;
mapping(address => bool) private _claimed;
constructor(address bpx) {
if (bpx.code.length == 0) {
revert Errors.NotAContract();
}
_claim.bpxContract = IERC20(bpx);
}
function bpxSupply() public view returns (uint256) {
return _claim.bpxContract.balanceOf(address(this));
}
function getClaimMetadata() public view returns (ClaimWindow memory) {
return _claim;
}
function claimed(address claimant) public view returns (bool) {
return _claimed[claimant];
}
function withdraw(address recipient) external onlyAuthorized {
_claim.bpxContract.transfer(recipient, bpxSupply());
}
function setClaimWindow(uint48 startTime, uint48 endTime, bytes32 merkleRoot) external onlyAuthorized {
if (endTime < startTime) {
revert Errors.InvalidTimeRange(startTime, endTime);
}
_claim.startTime = startTime;
_claim.endTime = endTime;
authRoot = merkleRoot;
}
function claim(address recipient, uint256 quantity, bytes32[] calldata proof) external {
uint256 windowStart = _claim.startTime;
uint256 windowEnd = _claim.endTime;
IERC20 bpx = _claim.bpxContract;
if (block.timestamp < windowStart) {
revert Errors.ClaimWindowClosed();
}
if (block.timestamp > windowEnd) {
revert Errors.ClaimWindowClosed();
}
if (_claimed[recipient]) {
revert Errors.DuplicateCall();
}
bytes32 leaf = keccak256(abi.encodePacked(recipient, quantity));
if (!MerkleProofLib.verify(proof, authRoot, leaf)) {
revert Errors.UserPermissions();
}
_claimed[recipient] = true;
emit CurrencyClaimed(recipient, quantity, msg.sender);
bpx.transfer(recipient, quantity);
}
}
文件 2 的 5:Errors.sol
pragma solidity >=0.8.4 <0.9.0;
library Errors {
error LinkError();
error ArrayMismatch();
error OutOfRange(uint256 value);
error OutOfRangeSigned(int256 value);
error UnsignedOverflow(uint256 value);
error SignedOverflow(int256 value);
error DuplicateCall();
error NotAContract();
error InterfaceNotSupported();
error NotInitialized();
error BadSender(address expected, address caller);
error AddressTarget(address target);
error UserPermissions();
error InsufficientBalance(uint256 available, uint256 required);
error InsufficientSupply(uint256 supply, uint256 available, int256 requested);
error InsufficientAvailable(uint256 available, uint256 requested);
error InvalidToken(uint256 tokenId);
error TokenNotMintable(uint256 tokenId);
error MintingClosed();
error ClaimWindowClosed();
error ClaimActive();
error InvalidTimeRange(uint256 startTime, uint256 endTime);
error ERC1155Receiver();
error ContractPaused();
error PaymentFailed(uint256 amount);
error IncorrectPayment(uint256 required, uint256 provided);
error TooManyForTransaction(uint256 mintLimit, uint256 amount);
}
文件 3 的 5:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
文件 4 的 5:MerkleProofLib.sol
pragma solidity >=0.8.0;
library MerkleProofLib {
function verify(
bytes32[] calldata proof,
bytes32 root,
bytes32 leaf
) internal pure returns (bool isValid) {
assembly {
if proof.length {
let end := add(proof.offset, shl(5, proof.length))
let offset := proof.offset
for {} 1 {} {
let leafSlot := shl(5, gt(leaf, calldataload(offset)))
mstore(leafSlot, leaf)
mstore(xor(leafSlot, 32), calldataload(offset))
leaf := keccak256(0, 64)
offset := add(offset, 32)
if iszero(lt(offset, end)) { break }
}
}
isValid := eq(leaf, root)
}
}
}
文件 5 的 5:ProxyOwnable.sol
pragma solidity >=0.8.4 <0.9.0;
import { Errors } from "../library/errors/Errors.sol";
abstract contract ProxyOwnable {
address public _owner;
address public _proxy;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_setOwner(msg.sender);
}
function owner() public view virtual returns (address) {
return _owner;
}
function proxy() public view virtual returns (address) {
return _proxy;
}
modifier onlyOwner() {
if (owner() != msg.sender) revert Errors.UserPermissions();
_;
}
modifier onlyAuthorized() {
if (
proxy() != msg.sender &&
owner() != msg.sender
) revert Errors.UserPermissions();
_;
}
function checkAuthorized(address operator) public view virtual {
if (
proxy() != operator &&
owner() != operator
) revert Errors.UserPermissions();
}
function renounceOwnership() public virtual onlyOwner {
_setOwner(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) revert Errors.AddressTarget(newOwner);
_setOwner(newOwner);
}
function setProxy(address newProxy) public virtual onlyOwner {
_proxy = newProxy;
}
function _setOwner(address newOwner) internal {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
{
"compilationTarget": {
"contracts/BpxClaim.sol": "BpxClaim"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"bpx","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressTarget","type":"error"},{"inputs":[],"name":"ClaimWindowClosed","type":"error"},{"inputs":[],"name":"DuplicateCall","type":"error"},{"inputs":[{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"}],"name":"InvalidTimeRange","type":"error"},{"inputs":[],"name":"NotAContract","type":"error"},{"inputs":[],"name":"UserPermissions","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"claimant","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"operator","type":"address"}],"name":"CurrencyClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"_owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_proxy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bpxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"checkAuthorized","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"claimant","type":"address"}],"name":"claimed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getClaimMetadata","outputs":[{"components":[{"internalType":"contract IERC20","name":"bpxContract","type":"address"},{"internalType":"uint48","name":"startTime","type":"uint48"},{"internalType":"uint48","name":"endTime","type":"uint48"}],"internalType":"struct BpxClaim.ClaimWindow","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint48","name":"startTime","type":"uint48"},{"internalType":"uint48","name":"endTime","type":"uint48"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"name":"setClaimWindow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newProxy","type":"address"}],"name":"setProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]