编译器
0.8.18+commit.87f61d96
文件 1 的 2:ClaimerContract.sol
pragma solidity =0.8.18;
import "./ClaimerHelper.sol";
contract ClaimerContract is ClaimerHelper {
address public immutable collector;
uint256 public immutable createTime;
uint256 public immutable minimumTime;
struct KeeperInfo {
uint256 keeperRate;
uint256 keeperTill;
uint256 keeperInstant;
uint256 keeperPayouts;
}
mapping(address => KeeperInfo) public keeperList;
modifier onlyCollector() {
require(
msg.sender == collector,
"ClaimerContract: INVALID_COLLECTOR"
);
_;
}
constructor(
address _collector,
uint256 _timeFrame,
address _tokenAddress
)
ClaimerHelper(
_tokenAddress
)
{
if (_timeFrame == 0) {
revert("ClaimerContract: INVALID_TIMEFRAME");
}
collector = _collector;
createTime = getNow();
minimumTime = _timeFrame;
}
function enrollAndScrape(
address _recipient,
uint256 _tokensLocked,
uint256 _tokensOpened,
uint256 _timeFrame
)
external
onlyCollector
{
_enrollRecipient(
_recipient,
_tokensLocked,
_tokensOpened,
_timeFrame
);
_scrapeTokens(
_recipient
);
}
function _enrollRecipient(
address _recipient,
uint256 _tokensLocked,
uint256 _tokensOpened,
uint256 _timeFrame
)
private
{
require(
keeperList[_recipient].keeperTill == 0,
"ClaimerContract: RECIPIENT_ALREADY_ENROLLED"
);
_allocateTokens(
_recipient,
_tokensLocked,
_tokensOpened,
_timeFrame
);
}
function _allocateTokens(
address _recipient,
uint256 _tokensLocked,
uint256 _tokensOpened,
uint256 _timeFrame
)
private
{
require(
_timeFrame >= minimumTime,
"ClaimerContract: INVALID_TIME_FRAME"
);
totalRequired = totalRequired
+ _tokensOpened
+ _tokensLocked;
keeperList[_recipient].keeperTill = createTime
+ _timeFrame;
keeperList[_recipient].keeperRate = _tokensLocked
/ _timeFrame;
keeperList[_recipient].keeperInstant = _tokensLocked
% _timeFrame
+ _tokensOpened;
_checkBalance(
totalRequired
);
emit recipientEnrolled(
_recipient,
_timeFrame,
_tokensLocked,
_tokensOpened
);
}
function scrapeMyTokens()
external
{
_scrapeTokens(
msg.sender
);
}
function _scrapeTokens(
address _recipient
)
private
{
uint256 scrapeAmount = availableBalance(
_recipient
);
keeperList[_recipient].keeperPayouts += scrapeAmount;
_safeScrape(
_recipient,
scrapeAmount
);
emit tokensScraped(
_recipient,
scrapeAmount,
getNow()
);
}
function availableBalance(
address _recipient
)
public
view
returns (uint256 balance)
{
uint256 timeNow = getNow();
uint256 timeMax = keeperList[_recipient].keeperTill;
if (timeMax == 0) return 0;
uint256 timePassed = timeNow > timeMax
? timeMax - createTime
: timeNow - createTime;
balance = keeperList[_recipient].keeperRate
* timePassed
+ keeperList[_recipient].keeperInstant
- keeperList[_recipient].keeperPayouts;
}
function lockedBalance(
address _recipient
)
external
view
returns (uint256 balance)
{
uint256 timeNow = getNow();
uint256 timeRemaining =
keeperList[_recipient].keeperTill > timeNow ?
keeperList[_recipient].keeperTill - timeNow : 0;
balance = keeperList[_recipient].keeperRate
* timeRemaining;
}
}
文件 2 的 2:ClaimerHelper.sol
pragma solidity =0.8.18;
contract ClaimerHelper {
uint256 public totalRequired;
address public immutable wiserToken;
event recipientEnrolled(
address indexed recipient,
uint256 timeFrame,
uint256 tokensLocked,
uint256 tokensOpened
);
event tokensScraped(
address indexed scraper,
uint256 scrapedAmount,
uint256 timestamp
);
constructor(
address _wiserTokenAddress
) {
if (_wiserTokenAddress == address(0x0)) {
revert("ClaimerHelper: INVALID_TOKEN");
}
wiserToken = _wiserTokenAddress;
}
bytes4 private constant TRANSFER = bytes4(
keccak256(
bytes(
"transfer(address,uint256)"
)
)
);
bytes4 private constant BALANCEOF = bytes4(
keccak256(
bytes(
"balanceOf(address)"
)
)
);
function _safeScrape(
address _to,
uint256 _scrapeAmount
)
internal
{
totalRequired -= _scrapeAmount;
(bool success, bytes memory data) = wiserToken.call(
abi.encodeWithSelector(
TRANSFER,
_to,
_scrapeAmount
)
);
require(
success && (
abi.decode(
data, (bool)
)
),
"ClaimerHelper: TRANSFER_FAILED"
);
}
function _checkBalance(
uint256 _required
)
internal
{
(bool success, bytes memory data) = wiserToken.call(
abi.encodeWithSelector(
BALANCEOF,
address(this)
)
);
require(
success && abi.decode(
data, (uint256)
) >= _required,
"ClaimerHelper: BALANCE_CHECK_FAILED"
);
}
function getNow()
public
view
returns (uint256 time)
{
time = block.timestamp;
}
}
{
"compilationTarget": {
"ClaimerContract.sol": "ClaimerContract"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_collector","type":"address"},{"internalType":"uint256","name":"_timeFrame","type":"uint256"},{"internalType":"address","name":"_tokenAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"timeFrame","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokensLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokensOpened","type":"uint256"}],"name":"recipientEnrolled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"scraper","type":"address"},{"indexed":false,"internalType":"uint256","name":"scrapedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"tokensScraped","type":"event"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"}],"name":"availableBalance","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"createTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_tokensLocked","type":"uint256"},{"internalType":"uint256","name":"_tokensOpened","type":"uint256"},{"internalType":"uint256","name":"_timeFrame","type":"uint256"}],"name":"enrollAndScrape","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getNow","outputs":[{"internalType":"uint256","name":"time","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"keeperList","outputs":[{"internalType":"uint256","name":"keeperRate","type":"uint256"},{"internalType":"uint256","name":"keeperTill","type":"uint256"},{"internalType":"uint256","name":"keeperInstant","type":"uint256"},{"internalType":"uint256","name":"keeperPayouts","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"}],"name":"lockedBalance","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"scrapeMyTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalRequired","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wiserToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]