Contracts
SnowsightManager.sol
0x727Dc3C412cCb942c6b5f220190ebAB3eFE0Eb93
/**
*Submitted for verification at snowtrace.io on 2022-05-12
*/
// ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄
// ▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌ ▐░▌ ▐░░░░░░░░░░░▌▐░░░░░░░░░░▌ ▐░░░░░░░░░░░▌
// ▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌▐░█▀▀▀▀▀▀▀█░▌ ▀▀▀▀█░█▀▀▀▀ ▐░▌░▌ ▐░▌▐░█▀▀▀▀▀▀▀▀▀ ▀▀▀▀█░█▀▀▀▀ ▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌ ▀▀▀▀█░█▀▀▀▀ ▐░▌ ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀▀▀
// ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌▐░▌
// ▐░▌ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄█░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌ ▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌ ▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄▄▄
// ▐░▌ ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░░░░░░░░░░░▌ ▐░▌ ▐░▌▐░░░░░░░░▌▐░░░░░░░░░░░▌ ▐░▌ ▐░▌ ▐░░░░░░░░░░░▌▐░░░░░░░░░░▌ ▐░░░░░░░░░░░▌
// ▐░▌ ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▀▀▀▀▀▀▀▀▀█░▌ ▐░▌ ▐░▌ ▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌ ▐░▌ ▐░▌ ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌ ▀▀▀▀▀▀▀▀▀█░▌
// ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌
// ▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌▐░▌ ▐░▌ ▄▄▄▄█░█▄▄▄▄ ▐░▌ ▐░▐░▌ ▄▄▄▄▄▄▄▄▄█░▌ ▄▄▄▄█░█▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌▐░▌ ▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌▐░█▄▄▄▄▄▄▄█░▌ ▄▄▄▄▄▄▄▄▄█░▌
// ▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░▌ ▐░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌ ▐░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░░░░░░░░░▌ ▐░░░░░░░░░░░▌
// ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀
//
// .----------------. .-----------------..----------------. .----------------. .----------------. .----------------. .----------------. .----------------. .----------------.
// | .--------------. | .--------------. | .--------------. | .--------------. | .--------------. | .--------------. | .--------------. | .--------------. | .--------------. |
// | | _______ | | | ____ _____ | | | ____ | | | _____ _____ | | | _______ | | | _____ | | | ______ | | | ____ ____ | | | _________ | |
// | | / ___ | | | ||_ \|_ _| | | | .' `. | | ||_ _||_ _|| | | / ___ | | | | |_ _| | | | .' ___ | | | | |_ || _| | | | | _ _ | | |
// | | | (__ \_| | | | | \ | | | | | / .--. \ | | | | | /\ | | | | | | (__ \_| | | | | | | | | / .' \_| | | | | |__| | | | | |_/ | | \_| | |
// | | '.___`-. | | | | |\ \| | | | | | | | | | | | | |/ \| | | | | '.___`-. | | | | | | | | | | ____ | | | | __ | | | | | | | |
// | | |`\____) | | | | _| |_\ |_ | | | \ `--' / | | | | /\ | | | | |`\____) | | | | _| |_ | | | \ `.___] _| | | | _| | | |_ | | | _| |_ | |
// | | |_______.' | | ||_____|\____| | | | `.____.' | | | |__/ \__| | | | |_______.' | | | |_____| | | | `._____.' | | | |____||____| | | | |_____| | |
// | | ******* | | | ******* | | | ******* | | | ******* | | | ******* | | | ******* | | | ******* | | | ******* | | | ******* | |
// | '--------------' | '--------------' | '--------------' | '--------------' | '--------------' | '--------------' | '--------------' | '--------------' | '--------------' |
// '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------'
//
// Version: 2
// May 9, 2022
//
pragma solidity 0.8.13;
abstract contract IERC20
{
function transfer(address to, uint value) virtual external returns (bool);
}
struct PaymentTierSettings
{
uint256 ratePerSecond;
uint256 timeMaximum;
uint256 timeMinimum;
bool enabled;
}
struct PaymentEntry
{
bool exists;
uint endTimestamp;
}
contract SnowsightManager
{
address public admin;
address public feeCollector;
uint8 public constant version = 2;
enum paymentTierTypes
{
FREE,
STANDARD,
PRIORITY
}
uint constant numPaymentTiers = 3;
PaymentTierSettings[numPaymentTiers] public tierSettings;
mapping(address => PaymentEntry[numPaymentTiers]) public payments;
event AccountPayment(address account, uint256 payment, uint256 endTimestamp);
constructor()
{
admin = msg.sender;
feeCollector = msg.sender;
for (uint i = 0 ; i < numPaymentTiers; i++)
{
tierSettings[i].enabled = true;
}
tierSettings[uint(paymentTierTypes.FREE)].ratePerSecond = 1;
tierSettings[uint(paymentTierTypes.STANDARD)].ratePerSecond = 3360215053763;
tierSettings[uint(paymentTierTypes.PRIORITY)].ratePerSecond = 12445240939864;
tierSettings[uint(paymentTierTypes.FREE)].timeMaximum = 1 days;
tierSettings[uint(paymentTierTypes.STANDARD)].timeMaximum = 60 days;
tierSettings[uint(paymentTierTypes.PRIORITY)].timeMaximum = 60 days;
tierSettings[uint(paymentTierTypes.FREE)].timeMinimum = 1 days;
tierSettings[uint(paymentTierTypes.STANDARD)].timeMinimum = 3 days;
tierSettings[uint(paymentTierTypes.PRIORITY)].timeMinimum = 3 days;
}
modifier onlyValidTier(uint tier) {
require (tier < numPaymentTiers);
_;
}
modifier onlyAdmin {
require (msg.sender == admin, "ERR_ADMIN_PROTECT");
_;
}
// Function to receive Ether. msg.data must be empty
receive() external payable {}
// Fallback function is called when msg.data is not empty
fallback() external payable {}
function setAdmin(address payable newAdmin) external onlyAdmin
{
admin = newAdmin;
}
function setFeeCollector(address payable newfeeCollector) external onlyAdmin
{
feeCollector = newfeeCollector;
}
function setPaymentsEnabled(uint tier, bool enabled) external onlyAdmin onlyValidTier(tier)
{
tierSettings[tier].enabled = enabled;
}
function setPaymentRatePerSecond(uint tier, uint256 newPaymentRatePerSecond) external onlyAdmin onlyValidTier(tier)
{
tierSettings[tier].ratePerSecond = newPaymentRatePerSecond;
}
function setMaximumPaymentTime(uint tier, uint256 newPaymentTimeMaximum) external onlyAdmin onlyValidTier(tier)
{
tierSettings[tier].timeMaximum = newPaymentTimeMaximum;
}
function setMinimumPaymentTime(uint tier, uint256 newPaymentTimeMinimum) external onlyAdmin onlyValidTier(tier)
{
tierSettings[tier].timeMinimum = newPaymentTimeMinimum;
}
function calculateMaxPayment(uint tier) public onlyValidTier(tier) view returns (uint256)
{
return calculate_max_payment(msg.sender, tier);
}
function calculateMinPayment(uint tier) public onlyValidTier(tier) view returns (uint256)
{
return tierSettings[tier].timeMinimum * tierSettings[tier].ratePerSecond;
}
function calculatePaymentByTierAndTime(uint tier, uint256 _seconds) public onlyValidTier(tier) view returns (uint256)
{
uint256 payment = _seconds * tierSettings[tier].ratePerSecond;
require (payment <= calculate_max_payment(msg.sender, tier), "ERROR_PAYMENT_TOO_LARGE");
require (payment >= tierSettings[tier].timeMinimum * tierSettings[tier].ratePerSecond, "ERROR_PAYMENT_TOO_SMALL");
return payment;
}
function calculate_max_payment(address payer, uint tier) internal view returns (uint256)
{
uint256 maxPayment = 0;
if (payments[payer][tier].exists && payments[payer][tier].endTimestamp > block.timestamp)
{
maxPayment = (tierSettings[tier].timeMaximum - (payments[payer][tier].endTimestamp - block.timestamp)) * tierSettings[tier].ratePerSecond;
}
else
{
maxPayment = tierSettings[tier].timeMaximum * tierSettings[tier].ratePerSecond;
}
return maxPayment;
}
function pay(uint tier) external payable onlyValidTier(tier)
{
require (tierSettings[tier].enabled == true, "ERROR_PAYMENTS_DISABLED");
require (msg.value <= calculate_max_payment(msg.sender, tier), "ERROR_PAYMENT_TOO_LARGE");
require (msg.value >= calculateMinPayment(tier), "ERROR_PAYMENT_TOO_SMALL");
if (payments[msg.sender][tier].exists)
{
if (payments[msg.sender][tier].endTimestamp > block.timestamp)
{
// account has a payment active
payments[msg.sender][tier].endTimestamp = payments[msg.sender][tier].endTimestamp + (msg.value / tierSettings[tier].ratePerSecond);
}
else
{
// account exists, but payment expired
payments[msg.sender][tier].endTimestamp = block.timestamp + (msg.value / tierSettings[tier].ratePerSecond);
}
}
else
{
// account does not exist yet
payments[msg.sender][tier].exists = true;
payments[msg.sender][tier].endTimestamp = block.timestamp + (msg.value / tierSettings[tier].ratePerSecond);
}
emit AccountPayment(msg.sender, msg.value, payments[msg.sender][tier].endTimestamp);
payable(feeCollector).transfer(msg.value);
}
function grant(address[] calldata addresses, uint256[] calldata timestamps, uint8[] calldata tiers) onlyAdmin external
{
for (uint i = 0; i < addresses.length; i++)
{
if (payments[addresses[i]][tiers[i]].exists == false)
{
payments[addresses[i]][tiers[i]].exists = true;
}
payments[addresses[i]][tiers[i]].endTimestamp = timestamps[i];
}
}
function transferEth(uint256 amount) onlyAdmin external
{
payable(msg.sender).transfer(amount);
}
function transferToken(address tokenAddress, uint256 amount) onlyAdmin external
{
IERC20 token = IERC20(tokenAddress);
token.transfer(msg.sender, amount);
}
}
Last updated