Description:
Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// lib/cyphermate/src/access/Blocklistable.sol
abstract contract Blocklistable {
event Blocklisted(address indexed operator, address indexed wallet, bool blocklisted);
mapping(address => bool) internal _blocklisted;
function _setBlocklist(address[] memory wallets_, bool blocklisted_) internal virtual {
for (uint256 i; i < wallets_.length;) {
_blocklisted[wallets_[i]] = blocklisted_;
emit Blocklisted(msg.sender, wallets_[i], blocklisted_);
unchecked { ++i; }
}
}
function _isBlocklisted(address wallet_) internal virtual view returns (bool) {
return _blocklisted[wallet_];
}
modifier notBlocklisted(address wallet_) {
require(!_blocklisted[wallet_], "WALLET_BLOCKLISTED");
_;
}
bytes32[50] private __padding;
}
// lib/cyphermate/src/access/Ownable.sol
// ERC-173 Compliant -> https://eips.ethereum.org/EIPS/eip-173
abstract contract Ownable {
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
address public owner;
modifier onlyOwner() virtual {
require (msg.sender == owner, "Ownable::onlyOwner: NOT_OWNER");
_;
}
constructor (address owner_) {
_transferOwnership(owner_);
}
function _transferOwnership(address newOwner_) internal virtual {
address _oldOwner = owner;
owner = newOwner_;
emit OwnershipTransferred(_oldOwner, newOwner_);
}
function transferOwnership(address newOwner_) public virtual onlyOwner {
require(newOwner_ != address(0),
"Ownable::transferOwnership: ZERO_ADDRESS_TRANSFER");
_transferOwnership(newOwner_);
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
bytes32[50] private __padding;
}
// src/dependencies/ERC20.sol
// EIP-20 Compliant -> https://eips.ethereum.org/EIPS/eip-20
// Forked from CypherLabz/Cyphermate
abstract contract ERC20 {
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
string public name;
string public symbol;
// Override decimals using a function override here
function decimals() public view virtual returns (uint8) {
return 18;
}
constructor(string memory name_, string memory symbol_) {
name = name_;
symbol = symbol_;
}
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
function _mint(address to_, uint256 amount_) internal virtual {
require(to_ != address(0), "ERC20: _mint to zero");
totalSupply += amount_;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to_] += amount_;
}
emit Transfer(address(0), to_, amount_);
}
function _burn(address from_, uint256 amount_) internal virtual {
require(from_ != address(0), "ERC20: _burn from zero");
// Fork: added verbose errors
uint256 _bal = balanceOf[from_];
require(_bal >= amount_, "ERC20: _burn insufficient balance");
balanceOf[from_] -= amount_;
// Cannot underflow because a user's balance
// will never be larger than the total supply.
unchecked {
totalSupply -= amount_;
}
emit Transfer(from_, address(0), amount_);
}
function _transfer(address from_, address to_, uint256 amount_) internal virtual {
require(from_ != address(0), "ERC20: _transfer from_ zero");
require(to_ != address(0), "ERC20: _transfer to_ zero");
// Fork: added verbose errors
uint256 _bal = balanceOf[from_];
require(_bal >= amount_, "ERC20: _transfer insufficient balance");
balanceOf[from_] -= amount_; // underflow-as-require
// Cannot overflow because the sum of all user
// balances can't exceed max uint256 value.
unchecked {
balanceOf[to_] += amount_;
}
emit Transfer(from_, to_, amount_);
}
function _spendAllowance(address from_, address operator_, uint256 amount_)
internal virtual {
if (allowance[from_][operator_] != type(uint256).max) {
allowance[from_][operator_] -= amount_; // underflow-as-require
}
}
function _approve(address owner_, address spender_, uint256 amount_) internal virtual {
allowance[owner_][spender_] = amount_;
emit Approval(owner_, spender_, amount_);
}
function approve(address spender_, uint256 amount_) public virtual returns (bool) {
_approve(msg.sender, spender_, amount_);
return true;
}
function transfer(address to_, uint256 amount_) public virtual returns (bool) {
_transfer(msg.sender, to_, amount_);
return true;
}
function transferFrom(address from_, address to_, uint256 amount_) public virtual returns (bool) {
_spendAllowance(from_, msg.sender, amount_);
_transfer(from_, to_, amount_);
return true;
}
bytes32[50] private __padding;
}
// lib/cyphermate/src/access/2step/Ownable2Step.sol
// Last update: 2024-02-12
// An extension of EIP-173 for a 2-step verification of ownership transfer.
abstract contract Ownable2Step is Ownable {
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
address public pendingOwner;
// Override Functions
function transferOwnership(address newOwner_) public virtual override(Ownable) onlyOwner {
pendingOwner = newOwner_;
emit OwnershipTransferStarted(msg.sender, newOwner_);
}
function _transferOwnership(address newOwner_) internal virtual override(Ownable) {
delete pendingOwner;
Ownable._transferOwnership(newOwner_);
}
// Non-Override Functions
function acceptOwnership() public virtual {
require(pendingOwner == msg.sender, "Ownable2Step: NOT_PENDING_OWNER");
Ownable2Step._transferOwnership(msg.sender);
}
function renounceOwnership() public virtual override(Ownable) onlyOwner {
delete pendingOwner;
Ownable.renounceOwnership();
}
bytes32[50] private __padding;
}
// lib/cyphermate/src/access/2step/Controllerable2Step.sol
// Last update: 2024-01-20
/**
* @title Controllerable: Dynamic Controller System
* @author 0xInuarashi
* @notice Controllerable is a role validation smart contract that expands ownable style roles into configurable roles, identified by a string.
* Solidity automatically converts a string key in a mapping into a bytes32 type automatically.
* Each controller type is identified by a string, so you can make an unlimited amount of controller types, such as "MINTER", "BURNER", "OPERATOR", then you can verify internally with onlyController("MINTER") or externally with isController("MINTER", <addressToLookup>)
*/
abstract contract Controllerable2Step is Ownable2Step {
event ControllerSet(address indexed owner, address indexed controller, string controllerType, bool status);
mapping(string => mapping(address => bool)) internal __controllers;
function isController(string memory type_, address controller_) public view virtual returns (bool) {
return __controllers[type_][controller_];
}
modifier onlyController(string memory type_) {
require(isController(type_, msg.sender), "Controllerable: NOT_CONTROLLER");
_;
}
function setController(string memory type_, address controller_, bool bool_) public virtual onlyOwner {
__controllers[type_][controller_] = bool_;
emit ControllerSet(msg.sender, controller_, type_, bool_);
}
bytes32[50] private __padding;
}
// src/SyndicateOfVigilantesTokenProxyable.sol
/**
---------------------------------------------------------------------------------------------------
| Group | Alloc% | Token Allocation | TGE% | Cliff (months) | Vesting (months) |
|-----------------------------|--------|------------------|-------|----------------|------------------|
| Player Incentives & Rewards | 27% | 270,000,000 | 0% | 2 | 36 |
| Ecosystem Treasury | 20% | 200,000,000 | 0% | 5 | 30 |
| Core Team | 10% | 100,000,000 | 0% | 16 | 36 |
| Private Seed Round | 9% | 90,000,000 | 0% | 4 | 9 |
| Strategic Advisory | 9% | 90,000,000 | 0% | 12 | 36 |
| TGE | 5% | 50,000,000 | 50% | 0 | 4 |
| Liquidity | 20% | 200,000,000 | 5% | 0 | 18 |
| Total | 100% | 1,000,000,000 | | | |
---------------------------------------------------------------------------------------------------
*/
contract SyndicateOfVigilantesTokenProxyable is ERC20, Controllerable2Step, Blocklistable {
// The constructor in this contract is intentionally empty.
// Initialization happens via the initialize() function when deployed through a proxy.
constructor()
Ownable(msg.sender)
ERC20("", "")
{
// Empty - actual initialization happens in initialize()
}
// Total MAX Supply of Tokens. All the constants add up to this.
uint256 public constant TOTAL_MAX_MINTED = 1_000_000_000 ether;
// Total MAX tokens and tracker for minted of each category
// Aligned with tokenomics XLSX: contract.xlsx
uint256 public constant PLAYER_INCENTIVES_MAX_MINTED = 270_000_000 ether; // 27% - Player Incentives & Rewards
uint256 public constant ECOSYSTEM_TREASURY_MAX_MINTED = 200_000_000 ether; // 20% - Ecosystem Treasury
uint256 public constant TEAM_MAX_MINTED = 100_000_000 ether; // 10% - Core Team
uint256 public constant PRIVATE_TOKEN_SALE_MAX_MINTED = 90_000_000 ether; // 9% - Private Seed Round
uint256 public constant ADVISORS_MAX_MINTED = 90_000_000 ether; // 9% - Strategic Advisory
/**
* @dev MONTH definition for vesting calculations
* TESTNET → 5 minutes for quick testing (e.g., 5 month cliff = 25 minutes, 30 months = 2.5 hours)
* MAINNET → Change to 30 days for production (e.g., 16 month cliff = 480 days)
*/
uint256 public constant MONTH = 30 days; // TODO: Change to 30 days for mainnet
// Total VEST time in seconds for each category (from XLSX)
uint256 public constant PLAYER_INCENTIVES_VEST = 36 * MONTH; // 36 months (3 years)
uint256 public constant ECOSYSTEM_TREASURY_VEST = 30 * MONTH; // 30 months (2.5 years)
uint256 public constant TEAM_VEST = 36 * MONTH; // 36 months (3 years)
uint256 public constant PRIVATE_TOKEN_SALE_VEST = 9 * MONTH; // 9 months
uint256 public constant ADVISORS_VEST = 36 * MONTH; // 36 months (3 years)
uint256 public constant TGE_VEST = 4 * MONTH; // 4 months (for remaining 50% of TGE)
uint256 public constant LIQUIDITY_VEST = 18 * MONTH; // 18 months (for remaining 95% of Liquidity)
// Cliff periods in seconds for each category (time before vesting starts)
uint256 public constant PLAYER_INCENTIVES_CLIFF = 2 * MONTH; // 2 months cliff
uint256 public constant ECOSYSTEM_TREASURY_CLIFF = 5 * MONTH; // 5 months cliff
uint256 public constant TEAM_CLIFF = 16 * MONTH; // 16 months cliff
uint256 public constant PRIVATE_TOKEN_SALE_CLIFF = 4 * MONTH; // 4 months cliff
uint256 public constant ADVISORS_CLIFF = 12 * MONTH; // 12 months cliff
uint256 public constant TGE_CLIFF = 0; // No cliff for TGE
uint256 public constant LIQUIDITY_CLIFF = 0; // No cliff for Liquidity
// Total TPS (Tokens Per Second) of each category
uint256 public constant PLAYER_INCENTIVES_TPS = PLAYER_INCENTIVES_MAX_MINTED / PLAYER_INCENTIVES_VEST;
// uint256 public constant ECOSYSTEM_TREASURY_TPS = ECOSYSTEM_TREASURY_MAX_MINTED / ECOSYSTEM_TREASURY_VEST;
uint256 public constant TEAM_TPS = TEAM_MAX_MINTED / TEAM_VEST;
uint256 public constant PRIVATE_TOKEN_SALE_TPS = PRIVATE_TOKEN_SALE_MAX_MINTED / PRIVATE_TOKEN_SALE_VEST;
uint256 public constant ADVISORS_TPS = ADVISORS_MAX_MINTED / ADVISORS_VEST;
// TGE and Liquidity vesting amounts and TPS
uint256 public constant TGE_MAX_MINTED = 50_000_000 ether; // 5% total (50M tokens)
uint256 public constant TGE_VESTING_AMOUNT = 25_000_000 ether; // 50% vests over 4 months
uint256 public constant TGE_TPS = TGE_VESTING_AMOUNT / TGE_VEST;
uint256 public constant LIQUIDITY_MAX_MINTED = 200_000_000 ether; // 20% total (200M tokens)
uint256 public constant LIQUIDITY_VESTING_AMOUNT = 190_000_000 ether; // 95% vests over 18 months
uint256 public constant LIQUIDITY_TPS = LIQUIDITY_VESTING_AMOUNT / LIQUIDITY_VEST;
/**
* @dev TGE unlock addresses and amounts
* TGE: 50% unlocked immediately (25M), 50% vests over 4 months (25M)
* Liquidity: 5% unlocked immediately (10M), 95% vests over 18 months (190M)
*/
// TGE and Liquidity immediate unlock addresses (set during initialize)
address public TGE_RECEIVER;
address public LIQUIDITY_RECEIVER;
uint256 public constant TGE_IMMEDIATE_UNLOCK = 25_000_000 ether; // 50% of TGE (2.5% of total supply)
uint256 public constant LIQUIDITY_IMMEDIATE_UNLOCK = 10_000_000 ether; // 5% of Liquidity (1% of total supply)
/** @dev YIELD_START_TIME - TESTNET: Set to current time for immediate testing */
uint256 public constant YIELD_START_TIME = 1759827600; // 2025-10-07 09:00:00 - CHANGE FOR MAINNET
/**
* @dev SSTORE trackers for minted counts of vested tokens
*/
uint256 public playerIncentivesTokensMinted;
uint256 public ecosystemTreasuryTokensMinted;
uint256 public teamTokensMinted;
uint256 public privateTokenSaleTokensMinted;
uint256 public advisorsTokensMinted;
uint256 public tgeTokensMinted;
uint256 public liquidityTokensMinted;
/**
* @dev the initialize paradigm for upgradeable proxies. It is used by proxies to initialize.
*/
bool public proxyInitialized;
function initialize(
address owner_,
address tgeReceiver_,
address liquidityReceiver_,
string memory name_,
string memory symbol_
) public {
require(!proxyInitialized, "PROXY_INITIALIZED");
require(tgeReceiver_ != address(0), "INVALID_TGE_RECEIVER");
require(liquidityReceiver_ != address(0), "INVALID_LIQUIDITY_RECEIVER");
require(bytes(name_).length > 0, "INVALID_NAME");
require(bytes(symbol_).length > 0, "INVALID_SYMBOL");
// Sanity check - verify total allocations equal max supply
require(
TOTAL_MAX_MINTED == (
PLAYER_INCENTIVES_MAX_MINTED +
ECOSYSTEM_TREASURY_MAX_MINTED +
TEAM_MAX_MINTED +
PRIVATE_TOKEN_SALE_MAX_MINTED +
ADVISORS_MAX_MINTED +
TGE_MAX_MINTED +
LIQUIDITY_MAX_MINTED
),
"TOTAL_SUPPLY_NOT_EQUAL"
);
// Set receiver addresses
TGE_RECEIVER = tgeReceiver_;
LIQUIDITY_RECEIVER = liquidityReceiver_;
// Ownable (Uses Controller2Step overridden _transferOwnership function)
_transferOwnership(owner_);
// ERC20
name = name_;
symbol = symbol_;
// Mint immediate unlock tokens
_mint(TGE_RECEIVER, TGE_IMMEDIATE_UNLOCK); // 25M TGE immediate
_mint(LIQUIDITY_RECEIVER, LIQUIDITY_IMMEDIATE_UNLOCK); // 10M Liquidity immediate
// Lock the initialization
proxyInitialized = true;
}
/**
* @dev _mint is overrided from ERC20 in order to add a TOTAL_MAX_MINTED check
*/
function _mint(address to_, uint256 amount_) internal virtual override(ERC20) notBlocklisted(to_) {
require(TOTAL_MAX_MINTED >= (totalSupply + amount_),
"SyndicateOfVigilantesToken: _mint exceeds MAX");
ERC20._mint(to_, amount_);
}
/**
* @dev blocklistable functionality and overrides for the token
*/
function adminSetBlocklist(address[] calldata wallets_, bool blocklisted_) public virtual
onlyController("ADMIN") {
_setBlocklist(wallets_, blocklisted_);
}
function _transfer(address from_, address to_, uint256 amount_) internal virtual
override(ERC20) notBlocklisted(from_) notBlocklisted(to_) {
ERC20._transfer(from_, to_, amount_);
}
/**
* @dev internal helper functions for calculations of values
*/
function _min(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? b : a;
}
function _getSecondsElapsed() internal view returns (uint256) {
return block.timestamp > YIELD_START_TIME ?
(block.timestamp - YIELD_START_TIME) : 0;
}
function _getAvailableTokens(uint256 maxTokens_, uint256 categoryTPS_,
uint256 currMinted_, uint256 cliffDuration_) internal view returns (uint256) {
uint256 _secondsElapsed = _getSecondsElapsed();
// Check if cliff period has passed
if (_secondsElapsed < cliffDuration_) {
return 0; // No tokens available during cliff period
}
// After cliff: tokens accumulate only from cliff end onwards
// Vesting starts AFTER the cliff period
uint256 _secondsSinceCliffEnd = _secondsElapsed - cliffDuration_;
uint256 _mintableTokensPerSecond = categoryTPS_;
uint256 _totalMintableTokens =
_min(
maxTokens_,
(_mintableTokensPerSecond * _secondsSinceCliffEnd)
);
uint256 _availableMintableTokens = _totalMintableTokens - currMinted_;
return _availableMintableTokens;
}
/**
* @dev abstracted _getAvailableTokens functions for each category.
* Created for code cleanliness.
*/
function availablePrivateSaleTokens() public view returns(uint256) {
return _getAvailableTokens(
PRIVATE_TOKEN_SALE_MAX_MINTED,
PRIVATE_TOKEN_SALE_TPS,
privateTokenSaleTokensMinted,
PRIVATE_TOKEN_SALE_CLIFF
);
}
function availablePlayerIncentivesTokens() public view returns (uint256) {
return _getAvailableTokens(
PLAYER_INCENTIVES_MAX_MINTED,
PLAYER_INCENTIVES_TPS,
playerIncentivesTokensMinted,
PLAYER_INCENTIVES_CLIFF
);
}
function availableEcosystemTreasuryTokens() public view returns (uint256) {
// Custom vesting schedule for Ecosystem Treasury
// Month 1 (after 5mo cliff): 16,666,667
// Months 2-29 (28 months): 6,333,333 each
// Month 30 (final): 6,000,000
// Total: 16,666,667 + (28 × 6,333,333) + 6,000,000 = 200,000,000
if (block.timestamp < YIELD_START_TIME) {
return 0;
}
uint256 timeSinceStart = block.timestamp - YIELD_START_TIME;
// Check cliff period (5 months)
if (timeSinceStart < ECOSYSTEM_TREASURY_CLIFF) {
return 0;
}
uint256 timeSinceCliff = timeSinceStart - ECOSYSTEM_TREASURY_CLIFF;
uint256 monthsSinceCliff = timeSinceCliff / MONTH;
uint256 vestedAmount;
if (monthsSinceCliff == 0) {
// Still in first month after cliff, nothing vested yet
vestedAmount = 0;
} else if (monthsSinceCliff == 1) {
// Month 1: 16,666,667 tokens
vestedAmount = 16_666_667 ether;
} else if (monthsSinceCliff <= 29) {
// Months 2-29: 16,666,667 + (monthsSinceCliff - 1) * 6,333,333
vestedAmount = 16_666_667 ether + ((monthsSinceCliff - 1) * 6_333_333 ether);
} else if (monthsSinceCliff == 30) {
// Month 30 (final): 16,666,667 + (28 * 6,333,333) + 6,000,000
vestedAmount = 16_666_667 ether + (28 * 6_333_333 ether) + 6_000_000 ether;
} else {
// Month 31+: All tokens (cap at 200M)
vestedAmount = ECOSYSTEM_TREASURY_MAX_MINTED;
}
// Return available (vested - already minted)
if (vestedAmount <= ecosystemTreasuryTokensMinted) {
return 0;
}
return vestedAmount - ecosystemTreasuryTokensMinted;
}
function availableAdvisorsTokens() public view returns (uint256) {
return _getAvailableTokens(
ADVISORS_MAX_MINTED,
ADVISORS_TPS,
advisorsTokensMinted,
ADVISORS_CLIFF
);
}
function availableTeamTokens() public view returns (uint256) {
return _getAvailableTokens(
TEAM_MAX_MINTED,
TEAM_TPS,
teamTokensMinted,
TEAM_CLIFF
);
}
function availableTGETokens() public view returns (uint256) {
return _getAvailableTokens(
TGE_VESTING_AMOUNT,
TGE_TPS,
tgeTokensMinted,
TGE_CLIFF
);
}
function availableLiquidityTokens() public view returns (uint256) {
return _getAvailableTokens(
LIQUIDITY_VESTING_AMOUNT,
LIQUIDITY_TPS,
liquidityTokensMinted,
LIQUIDITY_CLIFF
);
}
/**
* @dev minting functions for each category. Split into individual
* functions per category for code cleanliness.
*/
function privateTokenSaleMint(address to_, uint256 amount_) public
onlyController("PRIVATE_TOKEN_SALE_MINTER") {
require(availablePrivateSaleTokens() >= amount_,
"SyndicateOfVigilantesToken: privateTokenSale exceeds AVAILABLE");
uint256 _newMintedAmount = privateTokenSaleTokensMinted + amount_;
require(PRIVATE_TOKEN_SALE_MAX_MINTED >= _newMintedAmount,
"SyndicateOfVigilantesToken: privateTokenSaleMint exceeds MAX");
privateTokenSaleTokensMinted = _newMintedAmount;
_mint(to_, amount_);
}
function playerIncentivesMint(address to_, uint256 amount_) public
onlyController("PLAYER_INCENTIVES_MINTER") {
require(availablePlayerIncentivesTokens() >= amount_,
"SyndicateOfVigilantesToken: playerIncentives exceeds AVAILABLE");
uint256 _newMintedAmount = playerIncentivesTokensMinted + amount_;
require(PLAYER_INCENTIVES_MAX_MINTED >= _newMintedAmount,
"SyndicateOfVigilantesToken: playerIncentivesMint exceeds MAX");
playerIncentivesTokensMinted = _newMintedAmount;
_mint(to_, amount_);
}
function ecosystemTreasuryMint(address to_, uint256 amount_) public
onlyController("ECOSYSTEM_TREASURY_MINTER") {
require(availableEcosystemTreasuryTokens() >= amount_,
"SyndicateOfVigilantesToken: ecosystemTreasury exceeds AVAILABLE");
uint256 _newMintedAmount = ecosystemTreasuryTokensMinted + amount_;
require(ECOSYSTEM_TREASURY_MAX_MINTED >= _newMintedAmount,
"SyndicateOfVigilantesToken: ecosystemTreasuryMint exceeds MAX");
ecosystemTreasuryTokensMinted = _newMintedAmount;
_mint(to_, amount_);
}
function advisorsMint(address to_, uint256 amount_) public
onlyController("ADVISORS_MINTER") {
require(availableAdvisorsTokens() >= amount_,
"SyndicateOfVigilantesToken: advisorTokens exceeds AVAILABLE");
uint256 _newMintedAmount = advisorsTokensMinted + amount_;
require(ADVISORS_MAX_MINTED >= _newMintedAmount,
"SyndicateOfVigilantesToken: advisorsTokensMinted exceeds MAX");
advisorsTokensMinted = _newMintedAmount;
_mint(to_, amount_);
}
function teamMint(address to_, uint256 amount_) public
onlyController("TEAM_MINTER") {
require(availableTeamTokens() >= amount_,
"SyndicateOfVigilantesToken: teamTokens exceeds AVAILABLE");
uint256 _newMintedAmount = teamTokensMinted + amount_;
require(TEAM_MAX_MINTED >= _newMintedAmount,
"SyndicateOfVigilantesToken: teamTokensMinted exceeds MAX");
teamTokensMinted = _newMintedAmount;
_mint(to_, amount_);
}
function tgeMint(address to_, uint256 amount_) public
onlyController("TGE_MINTER") {
require(availableTGETokens() >= amount_,
"SyndicateOfVigilantesToken: tgeTokens exceeds AVAILABLE");
uint256 _newMintedAmount = tgeTokensMinted + amount_;
require(TGE_VESTING_AMOUNT >= _newMintedAmount,
"SyndicateOfVigilantesToken: tgeMint exceeds MAX");
tgeTokensMinted = _newMintedAmount;
_mint(to_, amount_);
}
function liquidityMint(address to_, uint256 amount_) public
onlyController("LIQUIDITY_MINTER") {
require(availableLiquidityTokens() >= amount_,
"SyndicateOfVigilantesToken: liquidityTokens exceeds AVAILABLE");
uint256 _newMintedAmount = liquidityTokensMinted + amount_;
require(LIQUIDITY_VESTING_AMOUNT >= _newMintedAmount,
"SyndicateOfVigilantesToken: liquidityMint exceeds MAX");
liquidityTokensMinted = _newMintedAmount;
_mint(to_, amount_);
}
// ERC20 "Safe" Functions
function increaseAllowance(address spender_, uint256 amount_) external
returns (bool) {
uint256 _currAllowance = ERC20.allowance[msg.sender][spender_];
_approve(msg.sender, spender_, (_currAllowance + amount_));
return true;
}
function decreaseAllowance(address spender_, uint256 amount_) external
returns (bool) {
uint256 _currAllowance = ERC20.allowance[msg.sender][spender_];
_approve(msg.sender, spender_, (_currAllowance - amount_));
return true;
}
}
Submitted on: 2025-10-06 16:57:45
Comments
Log in to comment.
No comments yet.