Solidity Version0.8.28
Optimizer Runs200
Contracts5
PSOL Max Supply100,000,000
Smart Contracts
Parasol Royalty Token
On-chain royalty entitlements for verified IP holders. 100M PSOL hard cap with time-locked release schedules.
Not yet deployed — run parasol-ip-protection deploy
pending
Parasol Access Token
Soulbound access credentials for Parasol IP Protection services (API, PARTNER, BLOCKCHAIN, ADMIN_DELEGATE).
Not yet deployed — run parasol-ip-protection deploy
pending
Parasol IP Licensing
Append-only registry of SYNC, MASTER, THEATRICAL, STREAMING, MERCHANDISE, and FULL_BUYOUT IP license agreements.
Not yet deployed — run parasol-ip-protection deploy
pending
Parasol IP Token
ERC-721 on-chain IP provenance token. Embeds IPFS hash, Clock Shaman timestamp, beacon hash, FTCA/RICO claim reference, royalty BPS, and litigation-protected status.
Not yet deployed — run parasol-ip-protection deploy
pending
Royalty Distributor
ETH revenue splitter for ParasolIPToken holders. Auto-earmarks 10% Impact Pledge (veterans, creators & justice). Token owners call claim() to withdraw their share.
Not yet deployed — run parasol-ip-protection deploy
pending
Contract BalanceNot deployed
Token #1 Claimable—
Impact Accumulated—
Impact Released—
NetworkBase Sepolia
Chain ID84532
Smart Contracts — Solidity Source
Solidity 0.8.28 · cancun// SPDX-License-Identifier: PROPRIETARY
// Copyright © William Joshua Drown, Dripsy Drown Productions Film & Entertainment™
// Parasol IP Protection — Royalty Token Contract
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
/**
* @title ParasolRoyaltyToken (PSOL)
* @notice ERC-20 royalty entitlement token for Parasol IP Protection.
* Only verified holders may receive or hold tokens.
* Royalties are scheduled on-chain with a time-lock and released
* exclusively by the contract owner (William Joshua Drown).
*/
contract ParasolRoyaltyToken is ERC20, ERC20Burnable, ERC20Permit, Ownable, ReentrancyGuard {
uint256 public constant MAX_SUPPLY = 100_000_000 * 1e18;
mapping(address => uint256) public royaltiesReleased;
mapping(address => bool) public verifiedHolders;
struct RoyaltySchedule {
address recipient;
uint256 amount;
uint256 releaseTimestamp;
bool released;
string projectId;
}
RoyaltySchedule[] public schedules;
event HolderVerified(address indexed holder, bool status);
event RoyaltyScheduled(uint256 indexed scheduleId, address indexed recipient, uint256 amount, string projectId);
event RoyaltyReleased(uint256 indexed scheduleId, address indexed recipient, uint256 amount);
constructor(address initialOwner)
ERC20("Parasol Royalty Token", "PSOL")
ERC20Permit("Parasol Royalty Token")
Ownable(initialOwner)
{}
function mint(address to, uint256 amount) external onlyOwner {
require(verifiedHolders[to], "ParasolRoyalty: recipient not verified");
require(totalSupply() + amount <= MAX_SUPPLY, "ParasolRoyalty: exceeds max supply");
_mint(to, amount);
}
function setVerifiedHolder(address holder, bool status) external onlyOwner {
verifiedHolders[holder] = status;
emit HolderVerified(holder, status);
}
function scheduleRoyalty(
address recipient, uint256 amount, uint256 releaseTimestamp, string calldata projectId
) external onlyOwner returns (uint256 scheduleId) {
require(verifiedHolders[recipient], "ParasolRoyalty: recipient not verified");
require(releaseTimestamp >= block.timestamp, "ParasolRoyalty: release time in the past");
require(totalSupply() + amount <= MAX_SUPPLY, "ParasolRoyalty: would exceed max supply");
scheduleId = schedules.length;
schedules.push(RoyaltySchedule(recipient, amount, releaseTimestamp, false, projectId));
emit RoyaltyScheduled(scheduleId, recipient, amount, projectId);
}
function releaseRoyalty(uint256 scheduleId) external onlyOwner nonReentrant {
RoyaltySchedule storage s = schedules[scheduleId];
require(!s.released, "ParasolRoyalty: already released");
require(block.timestamp >= s.releaseTimestamp, "ParasolRoyalty: not yet due");
require(totalSupply() + s.amount <= MAX_SUPPLY, "ParasolRoyalty: exceeds max supply");
s.released = true;
royaltiesReleased[s.recipient] += s.amount;
_mint(s.recipient, s.amount);
emit RoyaltyReleased(scheduleId, s.recipient, s.amount);
}
function scheduleCount() external view returns (uint256) {
return schedules.length;
}
// Soulbound transfer guard
function _update(address from, address to, uint256 value) internal override {
if (from != address(0) && to != address(0)) {
require(verifiedHolders[to] || to == owner(), "ParasolRoyalty: recipient not verified");
}
super._update(from, to, value);
}
}hardhat.config.ts
hardhat.config.ts — parasol-ip-protection
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
// Fail-fast: throws at startup if any required env var is missing
const requireEnv = (name: string): string => {
const value = process.env[name];
if (!value || value.trim() === "") throw new Error(`Missing env var: ${name}`);
return value;
};
const PRIVATE_KEY = requireEnv("PRIVATE_KEY");
const BASE_SEPOLIA_RPC_URL = requireEnv("BASE_SEPOLIA_RPC_URL");
const BASE_MAINNET_RPC_URL = requireEnv("BASE_MAINNET_RPC_URL");
const AMOY_RPC_URL = requireEnv("AMOY_RPC_URL");
const ETHERSCAN_API_KEY = requireEnv("ETHERSCAN_API_KEY");
const BASESCAN_API_KEY = requireEnv("BASESCAN_API_KEY");
const POLYGONSCAN_API_KEY = requireEnv("POLYGONSCAN_API_KEY");
const config: HardhatUserConfig = {
solidity: {
version: "0.8.28",
settings: { optimizer: { enabled: true, runs: 200 }, evmVersion: "cancun" },
},
paths: { sources: "./contracts", tests: "./test",
cache: "./cache", artifacts: "./artifacts" },
defaultNetwork: "baseSepolia",
networks: {
hardhat: {},
baseSepolia: { url: BASE_SEPOLIA_RPC_URL, chainId: 84532, accounts: [PRIVATE_KEY] },
base: { url: BASE_MAINNET_RPC_URL, chainId: 8453, accounts: [PRIVATE_KEY] },
polygonAmoy: { url: AMOY_RPC_URL, chainId: 80002, accounts: [PRIVATE_KEY] },
},
etherscan: {
apiKey: {
mainnet: ETHERSCAN_API_KEY, sepolia: ETHERSCAN_API_KEY,
base: BASESCAN_API_KEY, baseSepolia: BASESCAN_API_KEY,
polygon: POLYGONSCAN_API_KEY, polygonAmoy: POLYGONSCAN_API_KEY,
},
customChains: [
{ network: "base", chainId: 8453,
urls: { apiURL: "https://api.basescan.org/api",
browserURL: "https://basescan.org" } },
{ network: "baseSepolia", chainId: 84532,
urls: { apiURL: "https://api-sepolia.basescan.org/api",
browserURL: "https://sepolia.basescan.org" } },
{ network: "polygonAmoy", chainId: 80002,
urls: { apiURL: "https://api-amoy.polygonscan.com/api",
browserURL: "https://amoy.polygonscan.com" } },
],
},
};
export default config;