/**
* @title MiCA StableCoin for Stabillon sp z o.o.
* @author Billon Group / AH
*
* Copyright 2025 Billon Group, Ltd. All rights reserved.
* SPDX-License-Identifier: MIT
*
* @notice This is Interface for stablecoin with User-Centric Features: ERC-20 compatible and MiCA-compliant
*/
pragma solidity ^0.8.20;
// key interfaces for wide compatility with blockchain wallets and crypto exchanges
import { ISolidStateERC20 as IERC20 } from "@solidstate/contracts/token/ERC20/ISolidStateERC20.sol";
import { IAccessControl } from "@solidstate/contracts/access/access_control/IAccessControl.sol";
import "./StabillonStorage.sol";
/** =======================================================================
* IStabillonCoin
* -----------------------------------------------------------------------
* @title IStabillonCoin - The Stablecoin That Actually Gets It
*
* A stablecoin that doesn't sacrifice decentralization for compliance:
* - Multiple liquidity pools so you're not stuck in one jurisdiction
* - Governance that actually protects you from regulatory overreach and crazy developers
* - Sweet rewards for minters (because why should the big guys have all the fun?)
* - Transparent compliance stuff that won't make you pull your hair out
* ======================================================================= */
abstract contract IStabillonCoin is
IERC20, // Interface for key ERC-20 standard token
IAccessControl // Now using SolidState's IAccessControl
{
// ===============================================================
// Role Definitions
// ===============================================================
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
bytes32 public constant FREEZER_ROLE = keccak256("FREEZER_ROLE");
bytes32 public constant COMPLIANCE_ROLE = keccak256("COMPLIANCE_ROLE");
bytes32 public constant GOVERNANCE_ROLE = keccak256("GOVERNANCE_ROLE");
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant MASTER_MINTER_ROLE = keccak256("MASTER_MINTER_ROLE");
bytes32 public constant POOL_MINTER_ROLE = keccak256("POOL_MINTER_ROLE");
// ===============================================================
// 1. Core ERC20 Functions & Extensions
// NOTE: you have access to all standard ERC20 functions (OpenZeppelin)
// ===============================================================
/**
* IERC20 public functions inherited:
* - totalSupply() - Returns the total minted token supply in circulation
* - balanceOf(address) - Returns the token balance of a given account
* - transfer(address,uint256) - Transfers tokens to a given recipient
* - approve(address,uint256) - Grants approval to spender to spend tokens
* - transferFrom(address,address,uint256) - Transfers tokens on behalf of a holder
* - allowance(address,address) - Returns the allowance granted from holder to spender
* - increaseAllowance(address,uint256) - Increases spend amount granted to spender
* - decreaseAllowance(address,uint256) - Decreases spend amount granted to spender
*
* Metadata functions:
* - name() - Returns the token name
* - symbol() - Returns the token symbol
* - decimals() - Returns the token decimals (usually set to 2)
*
* Permit functions (EIP-2612):
* - DOMAIN_SEPARATOR() - Returns the EIP-712 domain separator for the contract
* - nonces(address) - Gets the current nonce for the given address
* - permit(address,address,uint256,uint256,uint8,bytes32,bytes32) - Approves tokens via signature
*/
/**
* @dev Transfers tokens with additional compliance data.
* @param recipient Address receiving tokens.
* @param amount Number of tokens to transfer.
* @param extraData Off-chain compliance data (e.g., travel rule hash).
* @return success True if transfer succeeds.
* Purpose: Supports AML and Travel Rule compliance.
*/
function transferWithCompliance(
address recipient,
uint256 amount,
LibStabillonStorage.DocumentationSubmission calldata extraData
) external virtual returns (bool);
/**
* @dev Transfers tokens using exclusively the specified fee batch.
* If the sender does not have sufficient tokens in that fee batch, the transfer reverts.
* @notice In some circumstances this may the most gas efficient way to transfer tokens, because
* it avoids the automatic fee batch selection algorithm that the base trasfer funtion needs to execute.
* @param recipient The address to transfer tokens to.
* @param amount The token amount to transfer.
* @param feeBatch The fee batch identifier to exclusively debit.
* @return True if the transfer succeeds.
*/
function transferWithFeeBatch(address recipient, uint256 amount, bytes32 feeBatch) external virtual returns (bool);
/**
* @dev Approves a spender (authorised user) using exclusively the specified fee batch.
* The approval will only be valid if the sender has sufficient balance in that fee batch
* (i.e. future transfers via transferFromWithFeeBatch will pull tokens only from that fee batch).
* If there is insufficient balance in that fee batch at the time of approval, the call reverts.
* @notice This function can only be called by the user (owner of the tokens)
* @param spender The address to approve.
* @param amount The token amount to approve.
* @param feeBatch The fee batch identifier to exclusively associate with the allowance.
* @return True if the approval is successful.
*/
function approveWithFeeBatch(address spender, uint256 amount, bytes32 feeBatch) external virtual returns (bool);
// ===============================================================
// 2. Token Supply: Minting & Redemption Management (money in circulation)
// ===============================================================
/**
* @dev The standard-derived mint function that follows basic stablecoin minting pattern.
* @notice This function automatically assigns either the default fee batch, or if user
* has registered for rewards the user's preferred fee batch to the minted tokens.
* @notice This function uses the default liquidity pool for our minter.
* @param to The address receiving the minted tokens.
* @param amount The amount of tokens to mint.
* uses reverts end emits error messages to communicate failure.
*/
function mint(address to, uint256 amount) external virtual;
/**
* @dev Prefered function to mint new tokens from a designated liquidity pool.
* @param to The recipient address that will receive the newly minted tokens.
* @param amount The number of tokens to mint.
* @param poolId Unique identifier for the liquidity pool. Different pools may be used for
* different jurisdictions (e.g. EU vs. US) to comply with local regulations.
* @param fiatReference IPFS hash of the bank statement attesting to the specific liqudity event backing mint operation.
*
* @dev Requirements:
* - Caller must have the MINTER_ROLE.
* - A daily attestation (bank statement) must be recorded for the pool. If the last attestation
* is older than ATTESTATION_INTERVAL, the caller must record a new attestation.
* - The IPFS hash is stored for transparency.
*
* MiCA Reference: Article 49 requires that token issuance is fully backed by fiat reserves,
* and regular attestation enhance transparency.
*/
function mintFromPool(address to, uint256 amount, uint256 poolId, string memory fiatReference) external virtual;
/**
* @dev Redeems tokens for fiat by burning tokens from the caller's balance.
* @param amount Number of tokens to redeem.
* @param processingTime Expected processing duration for off-chain redemption.
* @param maxGasFee Maximum technical network fee the user is willing to pay
*
* MiCA Art. 49: Ensures continuous redemption rights.
*/
function redeem(uint256 amount, uint256 processingTime, uint256 maxGasFee) external virtual;
/**
* @dev Provides a cryptographic attestation of reserve backing.
* @param poolId Liquidity pool identifier.
* @return A bytes32 cryptographic proof.
*
* MiCA Art. 49: Requires transparent reserve backing.
*/
function attestReserves(uint256 poolId) external virtual returns (bytes32);
// ===============================================================
// Liquidity Pool Management
// ===============================================================
/**
* @notice Gets the current total token supply with additional info
* @return totalSupply The total supply
* @return circulatingSupply The y
* @return frozenSupply The datance
* @return blacklistedSupply The d
*/
function getSupplyDetails() external view virtual returns (
uint256 totalSupply,
uint256 circulatingSupply,
uint256 frozenSupply,
uint256 blacklistedSupply
);
/**
* @dev Gets information about a liquidity pool
* @param poolId The unique identifier for the pool
* @return exists Whether the pool exists
* @return balance The current balance of the pool
* @return lastAttestationTime The timestamp of the last attestation
* @return lastAttestationHash The IPFS hash of the last attestation
*/
function getLiquidityPoolInfo(uint256 poolId) external view virtual returns (
bool exists,
uint256 balance,
uint256 lastAttestationTime,
string memory lastAttestationHash
);
/**
* @dev Gets the list of active pool IDs
* @return List of active pool IDs
*/
function getActivePools() external view virtual returns (uint256[] memory);
/**
* @dev Checks if a pool exists
* @param poolId The unique identifier for the pool
* @return Whether the pool exists
*/
function poolExists(uint256 poolId) external view virtual returns (bool);
/**
* @dev Gets the balance of a liquidity pool
* @param poolId The unique identifier for the pool
* @return The current balance of the pool, returns 0 if pool doesn't exist
*/
function getPoolBalance(uint256 poolId) external view virtual returns (uint256);
/**
* @dev Gets the last attestation timestamp for a pool
* @param poolId The unique identifier for the pool
* @return The timestamp of the last attestation, returns 0 if pool doesn't exist
*/
function getLastAttestationTime(uint256 poolId) external view virtual returns (uint256);
/**
* @dev Gets the last attestation hash for a pool
* @param poolId The unique identifier for the pool
* @return The IPFS hash of the last attestation, returns empty string if pool doesn't exist
*/
function getLastAttestationHash(uint256 poolId) external view virtual returns (string memory);
// ===============================================================
// 3. Rewards & Fee Batch Management
// ===============================================================
/**
* @dev Requests a specific fee batch and reward percentage for minted tokens.
* @param batchId The batch ID to request for future minting operations
* @param rewardPercentage The percentage of fees to be allocated as rewards (0-100)
* @return True if the request was submitted successfully
*
* @notice This function enables users to:
* - Request a specific fee batch for their minted tokens
* - Specify what percentage of those fees should be accumulated as rewards
* - The request must be approved by an admin before taking effect
*/
function requestRewardFeePreference(bytes32 batchId, uint256 rewardPercentage) external virtual returns (bool);
/**
* @dev Checks if a user has requested a fee preference
* @param user The address to check
* @return True if the user has a fee preference
*/
function hasRegisteredForRewardFee(address user) external view virtual returns (bool);
/**
* @dev Calculates cummulative rewards for a minter-helper based on their contribution history
* @param minter The address of the minter-helper
* @return The calculated rewards amount
* Purpose:
* This function provides an aggregate view of a minter’s rewards by calculating the total rewards accrued over the minter’s
* entire contribution history. In many reward schemes, the function internally iterates through contribution snapshots (or similar records)
* and computes a cumulative reward based on time weighting, multipliers, or other factors.
* Usage:
* It is intended as a quick “look-up” to see how many reward points or tokens a minter has earned overall
* It is not tied to a particular reward period or claim process.
*/
function calculateRewards(address minter) external view virtual returns (uint256);
/**
* @dev Gets a minter-helper's reward for a specific period
* @param minter The address of the minter-helper
* @param periodId The ID of the period, use 0 for most recent period rewards
* @return rewardAmount The reward amount
* @return claimed Whether the reward has been claimed
*
* @dev Requirements:
* - Caller must have negotiated a reward for the period.
*/
function getMinterRewardStatus(address minter, uint256 periodId) external view virtual returns (uint256 rewardAmount, bool claimed);
/**
* @dev Claims rewards for a minter-helper from a specific period
* @param minter The address of the minter-helper
* @param periodId The ID of the period
* @return rewardAmount The amount of rewards claimed
*
* @dev Requirements:
* - Caller must have negotiated a reward for the period.
* - Caller's proposal for fee batch must be approved and active.
* - The reward must be unclaimed.
*/
function claimReward(address minter, uint256 periodId) external virtual returns (uint256 rewardAmount);
/**
* @dev Gets the current fee preference for an address
* @param user The address to check
* @return batchId The batch ID for the user's preference
* @return rewardPercentage The percentage of fees allocated as rewards
* @return isActive Whether the preference is currently active
*/
function getFeePreference(address user) external view virtual returns (
bytes32 batchId,
uint256 rewardPercentage,
bool isActive
);
/**
* @dev Gets the batch types associated with a user.
* @param user Address to query.
* @return Array of batch identifiers.
*/
function getUserBatchTypes(address user) external view virtual returns (bytes32[] memory);
/**
* @dev Gets the balance of a specific batch for a user
* @param account The account to check
* @param batchId The batch ID
* @return The balance for the specified batch
*/
function getBatchBalance(address account, bytes32 batchId) external view virtual returns (uint256);
// /**
// * @dev Gets the fee percentage for a batch.
// * @param batchId Batch identifier.
// * @return Fee percentage in basis points (1/100 of a percent).
// */
// function getBatchFeePercentage(bytes32 batchId) external view virtual returns (uint256);
// ===============================================================
// 4. Compliance & Regulatory
// ===============================================================
/**
* @dev Checks if a transfer between two addresses is permitted
* @param from Sender address.
* @param to Recipient address.
* @return allowed True if transfer is allowed.
* @return reason Reason code if not allowed (0 = allowed, 1 = sender frozen, 2 = recipient frozen)
*/
function isTransferAllowed(address from, address to) external view virtual returns (bool allowed, uint8 reason);
/**
* @dev Removes an address from the on-chain blacklist.
* @param account Address to remove from blacklist.
*
* MiCA Art. 52: Allows external review-based unblocking.
*/
function isBlacklisted(address account) external view virtual returns (bool);
/**
* @dev Universal function for submitting any type of documentation or evidence
* @param appealType Related appeal type (if applicable)
* @param actionId Related compliance action ID (if applicable)
* @param documentation The documentation submission details
*
* @notice This function handles all types of documentation submission:
* - Evidence updates for appeals
* - Responses to documentation requests
* - Proactive documentation submission
*
* Emits appropriate events based on documentation type
*/
function submitOrUpdateDocumentation(
LibStabillonStorage.AppealReason appealType,
uint256 actionId,
LibStabillonStorage.DocumentationSubmission memory documentation
) external virtual;
/**
* @dev Files an objection to a pending freeze notice
* @param objectionReason The reason for the objection
* @param evidence Supporting documentation
*/
function fileFreezeObjection(
string calldata objectionReason,
LibStabillonStorage.DocumentationSubmission calldata evidence
) external virtual;
/**
* @dev Files an appeal against a compliance action
* @param appealType The type of appeal
* @param reason The reason for the appeal
* @param evidence Supporting documentation
* @return appealId Unique identifier for the appeal
*/
function fileAppeal(
LibStabillonStorage.AppealReason appealType,
string calldata reason,
LibStabillonStorage.DocumentationSubmission calldata evidence
) external virtual returns (uint256);
/**
* @dev Gets the details of an appeal
* @param appellant The address that filed the appeal
* @param appealType The type of appeal
* @return status Current status of the appeal
* @return filingTimestamp When the appeal was filed
* @return reviewTimestamp When the appeal was last reviewed
* @return approvalCount Number of approvals received
* @return rejectionCount Number of rejections received
* @return reason Reason provided for the appeal
*/
function getAppealDetails(
address appellant,
LibStabillonStorage.AppealReason appealType
) external view virtual returns (
uint8 status,
uint256 filingTimestamp,
uint256 reviewTimestamp,
uint256 approvalCount,
uint256 rejectionCount,
string memory reason
);
/**
* @dev Withdraws a pending appeal
* @param appealType The type of appeal to withdraw
*/
function withdrawAppeal(LibStabillonStorage.AppealReason appealType) external virtual;
// ===============================================================
// 5. Governance & Contract Upgrades
// ===============================================================
/**
* @dev Checks if an address is eligible to vote on governance decisions.
* @param account The address to check.
* @return Whether the address is eligible to vote.
*/
function isEligibleVoter(address account) external view virtual returns (bool);
/**
* @dev Allows governance members to approve a proposed upgrade.
* @param implementation The address of the implementation to approve.
*
* @notice Only governance members can approve upgrades. Token holders
* can only reject upgrades through a separate mechanism.
*/
function approveUpgrade(address implementation) public virtual;
/**
* @dev Allows token holders to reject a proposed upgrade.
*
* @notice This is part of the democratic safeguard mechanism where token holders
* can block an upgrade if sufficient opposition exists. Token holders cannot
* directly approve upgrades - only governance members can do that.
*/
function rejectUpgrade() external virtual;
/**
* @dev Gets current voter information.
* @return checkpointCount Current checkpoint ID.
* @return lastActivityTime Timestamp int.
* @return isRegistered Nums.
* @return hasVotedOnCurrentUpgrade Whether the address has voted on the current upgrade.
*/
function getVoterInfo() external view virtual returns (
uint256 checkpointCount,
uint256 lastActivityTime,
bool isRegistered,
bool hasVotedOnCurrentUpgrade
);
}