Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 189 additions & 0 deletions contracts/ vaults/PiRCAirdropVault.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IERC20 {
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
}

/*
PiRCAirdropVault

Wave-based community distribution vault for PiRC.

Features:
- 6 distribution waves
- Fixed unlock timestamps
- Per-wallet social platform claim mask
- Operator-controlled airdrops
- Excess withdrawal after final wave
*/

contract PiRCAirdropVault {

IERC20 public immutable PIRC;
address public operator;

uint256 private constant DEC = 1e18;

// Example issue timestamp
uint256 public constant ISSUE_TS = 1763865465;

// Unlock schedule
uint256 public constant W1 = ISSUE_TS + 14 days;
uint256 public constant W2 = W1 + 90 days;
uint256 public constant W3 = W2 + 90 days;
uint256 public constant W4 = W3 + 90 days;
uint256 public constant W5 = W4 + 90 days;
uint256 public constant W6 = W5 + 90 days;

uint256 public constant AFTER_ALL_WAVES = W6 + 90 days;

// Distribution caps
uint256 public constant CAP1 = 500_000 * DEC;
uint256 public constant CAP2 = 350_000 * DEC;
uint256 public constant CAP3 = 250_000 * DEC;
uint256 public constant CAP4 = 180_000 * DEC;
uint256 public constant CAP5 = 120_000 * DEC;
uint256 public constant CAP6 = 100_000 * DEC;

uint256 public constant TOTAL_ALLOCATION =
CAP1 + CAP2 + CAP3 + CAP4 + CAP5 + CAP6;

uint256 public totalDistributed;

// Social platform claim mask
// 1=Instagram, 2=X, 4=Telegram, 8=Facebook, 16=YouTube
mapping(address => uint8) public socialMask;

event OperatorUpdated(address oldOperator, address newOperator);
event Airdropped(address indexed to, uint256 amount, uint8 platformBit);
event WithdrawnExcess(address indexed to, uint256 amount);

modifier onlyOperator() {
require(msg.sender == operator, "NOT_OPERATOR");
_;
}

constructor(address _pircToken, address _operator) {
require(_pircToken != address(0), "TOKEN_ZERO");
require(_operator != address(0), "OPERATOR_ZERO");

PIRC = IERC20(_pircToken);
operator = _operator;

emit OperatorUpdated(address(0), operator);
}

function setOperator(address newOperator) external onlyOperator {
require(newOperator != address(0), "OPERATOR_ZERO");

address old = operator;
operator = newOperator;

emit OperatorUpdated(old, newOperator);
}

/* ========= WAVE LOGIC ========= */

function currentWave() public view returns (int8) {

uint256 t = block.timestamp;

if (t < W1) return -1;
if (t < W2) return 0;
if (t < W3) return 1;
if (t < W4) return 2;
if (t < W5) return 3;
if (t < W6) return 4;

return 5;
}

function unlockedTotal() public view returns (uint256) {

int8 w = currentWave();

if (w < 0) return 0;

uint256 sum = CAP1;

if (w >= 1) sum += CAP2;
if (w >= 2) sum += CAP3;
if (w >= 3) sum += CAP4;
if (w >= 4) sum += CAP5;
if (w >= 5) sum += CAP6;

return sum;
}

function remainingUnlocked() public view returns (uint256) {

uint256 unlocked = unlockedTotal();

if (totalDistributed >= unlocked) return 0;

return unlocked - totalDistributed;
}

/* ========= CLAIM ACTION ========= */

function airdrop(
address to,
uint256 amount,
uint8 platformBit
) external onlyOperator {

require(to != address(0), "TO_ZERO");
require(amount > 0, "AMOUNT_ZERO");

require(_validPlatform(platformBit), "BAD_PLATFORM");

uint8 mask = socialMask[to];

require((mask & platformBit) == 0, "ALREADY_CLAIMED");

require(remainingUnlocked() >= amount, "WAVE_CAP");

require(PIRC.balanceOf(address(this)) >= amount, "VAULT_LOW");

socialMask[to] = mask | platformBit;

totalDistributed += amount;

require(PIRC.transfer(to, amount), "TRANSFER_FAIL");

emit Airdropped(to, amount, platformBit);
}

/* ========= WITHDRAW EXCESS ========= */

function withdrawExcess(address to, uint256 amount)
external
onlyOperator
{

require(block.timestamp >= AFTER_ALL_WAVES, "TOO_EARLY");

uint256 bal = PIRC.balanceOf(address(this));

uint256 mustKeep = TOTAL_ALLOCATION - totalDistributed;

require(bal > mustKeep, "NO_EXCESS");

uint256 excess = bal - mustKeep;

require(amount <= excess, "TOO_MUCH");

require(PIRC.transfer(to, amount), "TRANSFER_FAIL");

emit WithdrawnExcess(to, amount);
}

/* ========= HELPERS ========= */

function _validPlatform(uint8 b) internal pure returns (bool) {
return (b == 1 || b == 2 || b == 4 || b == 8 || b == 16);
}

}
23 changes: 23 additions & 0 deletions contracts/Governance.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
* @title PiRC101Governance
* @dev Decentralized Governance framework for the Sovereign Monetary Standard.
*/
contract PiRC101Governance {
uint256 public constant SOVEREIGN_MULTIPLIER (QWF) = 10000000;
mapping(address => bool) public isVerifiedPioneer;

event ParameterChangeProposed(string parameter, uint256 newValue);
event VoteCast(address indexed pioneer, bool support);

/**
* @dev Proposes a change to the QWF multiplier based on ecosystem velocity.
*/
function proposeMultiplierAdjustment(uint256 newQWF) public {
require(isVerifiedPioneer[msg.sender], "Access Denied: Only verified Pioneers can propose.");
emit ParameterChangeProposed("QWF", newQWF);
}
}

160 changes: 160 additions & 0 deletions contracts/PiRC101Vault.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
* @title PiRC-101 Sovereign Vault (Hardened Reference Model)
* @author EslaM-X Protocol Architect
* @notice Formalizes 10M:1 Credit Expansion with Hardened Exit Throttling Logic and Unit Consistency (Deterministic Spec).
*/
contract PiRC101Vault {
// --- Constants ---
uint256 public constant QWF_MAX = 10_000_000; // 10 Million Multiplier
uint256 public constant EXIT_CAP_PPM = 1000; // 0.1% Daily Exit Limit

// --- State Variables ---
struct GlobalState {
uint256 totalReserves; // External Pi Locked
uint256 totalREF; // Total Internal Credits Minted
uint256 lastExitTimestamp;
uint256 dailyExitAmount;
}

GlobalState public systemState;
mapping(address => mapping(uint8 => uint256)) public userBalances;

// Provenance Invariant Psi: Track Mined vs External Status
mapping(address => bool) public isSnapshotWallet;

// --- Events ---
event CreditExpanded(address indexed user, uint256 piDeposited, uint256 refMinted, uint256 phi);
event CreditThrottledExit(address indexed user, uint256 refBurned, uint256 piWithdrawn, uint256 remainingCap);

/**
* @notice Deposits External Pi and Mints Internal REF Credits.
*/
function depositAndMint(uint256 _amount, uint8 _class) external {
require(_amount > 0, "Amount must be greater than zero");

// --- Placeholders for Oracle Integration (Decentralized Aggregation Required for Production) ---
// TODO: integrate decentralized oracle feed
uint256 piPrice = 314000; // $0.314 (scaled to 6 decimals)
uint256 currentLiquidity = 10_000_000 * 1e6; // $10M Market Depth (scaled to 6 decimals)

// --- Compute Phi first for the solvency guardrail ---
uint256 phi = calculatePhi(currentLiquidity, systemState.totalREF);

// --- Insolvency Guardrail Check ---
require(phi > 0, "Minting Paused: External Solvency Guardrail Activated.");

// --- Expansion Logic (Pi -> USD -> 10M REF) ---
uint256 capturedValue = (_amount * piPrice) / 1e6;

// --- Provenance Logic: Single wcf declaration to fix redeclaration error ---
uint256 wcf = 1e18; // 1.0 default (External Pi weight)
if (isSnapshotWallet[msg.sender]) {
wcf = 1e25; // Placeholder for high mined Pi weight (e.g., Wm = 1.0)
}

uint256 mintAmount = (capturedValue * QWF_MAX * phi * wcf) / 1e36;

// --- Update State ---
systemState.totalReserves += _amount;
systemState.totalREF += mintAmount;
userBalances[msg.sender][_class] += mintAmount;

// --- Emit Hardened Event ---
emit CreditExpanded(msg.sender, _amount, mintAmount, phi);
}

/**
* @notice Pure, deterministic calculation of the Phi guardrail invariant.
*/
function calculatePhi(uint256 _depth, uint256 _supply) public pure returns (uint256) {
if (_supply == 0) return 1e18; // 1.0 (Full Expansion)
uint256 ratio = (_depth * 1e18) / _supply; // simplified 1:1 QWF scaling assumption
if (ratio >= 1.5e18) return 1e18; // Healthy threshold (Gamma = 1.5)
return (ratio * ratio) / 2.25e18; // Quadratic Throttling (ratio^2 / Gamma^2)
}

// --- Hardened Exit Throttling Logic ---

/**
* @notice Conceptual Function for Withdrawal/Exit. Demonstrates the exit throttling mechanism.
* @dev Hardened: Fixes unit consistency issue by comparing USD to USD.
* @param _refAmount REF Credits user wants to liquidate.
* @param _class Target utility class.
* @return piOut The actual Pi value (scaled Conceptual USD Value) conceptually withdrawn.
*/
function conceptualizeWithdrawal(uint256 _refAmount, uint8 _class) external returns (uint256 piOut) {
require(userBalances[msg.sender][_class] >= _refAmount, "Insufficient REF balance");

// --- Placeholders for Oracle Integration ---
// TODO: integrate decentralized oracle feed
uint256 piPrice = 314000; // $0.314 (scaled to 6 decimals)
uint256 currentLiquidity = 10_000_000 * 1e6; // $10M Market Depth

// --- Dynamic State Update: Calculate remaining exit cap ---
uint256 currentTime = block.timestamp;
if (currentTime >= systemState.lastExitTimestamp + 1 days) {
systemState.lastExitTimestamp = currentTime;
systemState.dailyExitAmount = 0; // Reset daily counter
}

// Available Exit Door (USD Depth * EXIT_CAP_PPM / 1e6)
uint256 availableDailyDoorUsd = (currentLiquidity * EXIT_CAP_PPM) / 1e6;
uint256 remainingDailyUsdCap = availableDailyDoorUsd > systemState.dailyExitAmount ? availableDailyDoorUsd - systemState.dailyExitAmount : 0;

// --- Conceptual Conversion and Throttling ---
// 1. Conceptualize REF USD Value: Simplified view
uint256 refUsdConceptualValue = (_refAmount * piPrice) / (QWF_MAX * 1e6);

// 2. Apply Throttling based on Remaining Daily USD Cap
// --- Fix: Unit consistency - comparing refUsdConceptualValue (USD) to remainingDailyUsdCap (USD) ---
uint256 allowedRefUsdValue = refUsdConceptualValue <= remainingDailyUsdCap ? refUsdConceptualValue : remainingDailyUsdCap;
piOut = (allowedRefUsdValue * 1e6) / piPrice; // Conceptualized Pi out

// 3. Final Invariant Check
require(piOut > 0, "Daily Exit Throttled: Zero Conceptual Withdrawal Allowed.");

// Update State
userBalances[msg.sender][_class] -= _refAmount;
systemState.totalREF -= _refAmount; // REF is conceptually burned

systemState.totalReserves -= piOut; // Solvency drain from Reserves conceptualized
systemState.dailyExitAmount += allowedRefUsdValue;

// --- Emit Hardened Event ---
emit CreditThrottledExit(msg.sender, _refAmount, piOut, remainingDailyUsdCap);
}
}
// Available Exit Door (USD Depth * EXIT_CAP_PPM / 1e6)
uint256 availableDailyDoorUsd = (currentLiquidity * EXIT_CAP_PPM) / 1e6;
uint256 remainingDailyUsdCap = availableDailyDoorUsd > systemState.dailyExitAmount ? availableDailyDoorUsd - systemState.dailyExitAmount : 0;

// --- Conceptual Conversion and Throttling ---
// 1. Conceptualize REF USD Value: Assume 1 Pi always buys fixed USD conceptual value
// Note: For a true stable system, 1 REF would target a fixed USD peg (e.g., $1/10M), which is missing in this view.
// For simplicity, we just convert the raw Pi value captured earlier.
uint256 refUsdConceptualValue = (_refAmount * piPrice) / (QWF_MAX * 1e6); // Simplified

// 2. Apply Throttling based on Remaining Daily USD Cap
uint256 allowedRefUsdValue = _refAmount <= QWF_MAX ? refUsdConceptualValue : remainingDailyUsdCap;
piOut = (allowedRefUsdValue * 1e6) / piPrice; // Conceptualized Pi out

// 3. Final Invariant Solvency Check: Can the available exit door absorb this exit?
// This is where Phi's twin operates at the exit door. If too many REF try to crowd through, they get throttled.
if (refUsdConceptualValue > allowedRefUsdValue) {
// Extreme Throttling scenario: User gets back less conceptualized Pi.
piOut = (allowedRefUsdValue * 1e6) / piPrice;
}

// --- Execute Updates ---
userBalances[msg.sender][_class] -= _refAmount;
systemState.totalREF -= _refAmount; // REF is conceptually burned

systemState.totalReserves -= piOut; // Solvency drain from Reserves conceptualized
systemState.dailyExitAmount += allowedRefUsdValue;

emit CreditThrottledExit(msg.sender, _refAmount, piOut, remainingDailyUsdCap);
}
}
Loading