// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/**
* @title PrimehodVesting
* @notice One per launched token. Holds a reserved slice of supply (default 20%)
* and releases it to a beneficiary on a fixed schedule: `releasePerPeriod`
* tokens unlock every `periodSeconds`, until `totalAmount` is fully vested.
* The default schedule is 1% of total supply per 30 days over 20 months.
* @dev Identical mechanism to B20Vesting; the only change is that it drives a
* standard ERC-20 instead of the Base-native B20 asset. All parameters are
* IMMUTABLE: once a token launches its schedule is locked forever. No admin,
* no early-release, no rug path: tokens can only leave on schedule, and only
* ever to the immutable beneficiary.
*/
contract PrimehodVesting is ReentrancyGuard {
address public immutable token;
address public immutable beneficiary;
uint256 public immutable totalAmount; // total to vest (e.g. 20% of supply)
uint256 public immutable releasePerPeriod; // unlocked each period (e.g. 1% of supply)
uint256 public immutable periodSeconds; // period length (e.g. 30 days)
uint256 public immutable startTime;
uint256 public claimed;
event Claimed(address indexed beneficiary, uint256 amount);
constructor(
address _token,
address _beneficiary,
uint256 _totalAmount,
uint256 _releasePerPeriod,
uint256 _periodSeconds
) {
require(_token != address(0) && _beneficiary != address(0), "zero addr");
require(_totalAmount > 0 && _releasePerPeriod > 0 && _periodSeconds > 0, "bad schedule");
token = _token;
beneficiary = _beneficiary;
totalAmount = _totalAmount;
releasePerPeriod = _releasePerPeriod;
periodSeconds = _periodSeconds;
startTime = block.timestamp;
}
/// @notice Cumulative amount unlocked so far (capped at totalAmount). The first
/// period unlocks after one full `periodSeconds` (no day-0 cliff bypass).
function vested() public view returns (uint256) {
uint256 periods = (block.timestamp - startTime) / periodSeconds;
uint256 v = periods * releasePerPeriod;
return v > totalAmount ? totalAmount : v;
}
/// @notice Unlocked but not-yet-claimed amount.
function claimable() public view returns (uint256) {
return vested() - claimed;
}
/// @notice Claim all currently-unlocked tokens to the beneficiary. Permissionless
/// (funds can only ever go to the immutable beneficiary).
function claim() external nonReentrant {
uint256 amount = claimable();
require(amount > 0, "nothing to claim");
claimed += amount;
require(IERC20(token).transfer(beneficiary, amount), "transfer failed");
emit Claimed(beneficiary, amount);
}
}[
{
"type": "constructor",
"inputs": [
{
"name": "_token",
"type": "address",
"internalType": "address"
},
{
"name": "_beneficiary",
"type": "address",
"internalType": "address"
},
{
"name": "_totalAmount",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "_releasePerPeriod",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "_periodSeconds",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "nonpayable"
},
{
"name": "ReentrancyGuardReentrantCall",
"type": "error",
"inputs": []
},
{
"name": "Claimed",
"type": "event",
"inputs": [
{
"name": "beneficiary",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "amount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "beneficiary",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "claim",
"type": "function",
"inputs": [],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "claimable",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "claimed",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "periodSeconds",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "releasePerPeriod",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "startTime",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "token",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "totalAmount",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "vested",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
}
]0x608080604052600436101561001357600080fd5b60003560e01c9081631a39d8ef146104035750806338af3eed146103be5780634e71d92d146101f057806378e97925146101b5578063af38d7571461018e578063e5808f7814610153578063e834a83414610135578063f4514fa3146100fa578063fc0c546a146100b55763fea5657c1461008d57600080fd5b346100b05760003660031901126100b05760206100a8610449565b604051908152f35b600080fd5b346100b05760003660031901126100b0576040517f000000000000000000000000cdd2ddcd6ec799300b627bc3e12f30649b0d60d96001600160a01b03168152602090f35b346100b05760003660031901126100b05760206040517f0000000000000000000000000000000000000000000000000000000000278d008152f35b346100b05760003660031901126100b0576020600054604051908152f35b346100b05760003660031901126100b05760206040517f000000000000000000000000000000000000000000084595161401484a0000008152f35b346100b05760003660031901126100b05760206100a86101ac610449565b6000549061043c565b346100b05760003660031901126100b05760206040517f000000000000000000000000000000000000000000000000000000006a4907168152f35b346100b05760003660031901126100b057600260008051602061051883398151915254146103ad57600260008051602061051883398151915255610232610449565b61023f600054809261043c565b9081156100b05781810180911161039757600090815560405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000de46c8ad3eb5b3992f21721ce69f3d92ea07c96f81166004830181905260248301859052939260209183916044918391907f000000000000000000000000cdd2ddcd6ec799300b627bc3e12f30649b0d60d9165af190811561038b57600091610320575b50156100b05760207fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a91604051908152a2600160008051602061051883398151915255005b60203d602011610384575b601f8101601f191682016001600160401b038111838210176103705760209183916040528101031261036c57519081151582036103695750836102db565b80fd5b5080fd5b634e487b7160e01b84526041600452602484fd5b503d61032b565b6040513d6000823e3d90fd5b634e487b7160e01b600052601160045260246000fd5b633ee5aeb560e01b60005260046000fd5b346100b05760003660031901126100b0576040517f000000000000000000000000de46c8ad3eb5b3992f21721ce69f3d92ea07c96f6001600160a01b03168152602090f35b346100b05760003660031901126100b0576020907f000000000000000000000000000000000000000000a56fa5b99019a5c80000008152f35b9190820391821161039757565b6104737f000000000000000000000000000000000000000000000000000000006a4907164261043c565b7f0000000000000000000000000000000000000000000000000000000000278d0090811561050157047f000000000000000000000000000000000000000000084595161401484a00000090818102918183041490151715610397577f000000000000000000000000000000000000000000a56fa5b99019a5c800000090818111156104fc575090565b905090565b634e487b7160e01b600052601260045260246000fdfe9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a2646970667358221220c42a07e2cb5236d544b1f283490eeff89a785d5d59e22550ab52aa80d8a10e5364736f6c634300081a0033
| Token | Symbol | Balance | Price | Value |
|---|---|---|---|---|
| DIH | 1 | $0.0000102 | $0 | |
| test (TEST) | TEST | 200,000,000 | — | — |
| Transaction Hash | Method ? | Block | Age | From | To | Amount | Txn Fee ? | ||
|---|---|---|---|---|---|---|---|---|---|
| No direct transactions — this address is only ever reached via internal calls (common for a contract only invoked through a router or proxy). View Internal Transactions → | |||||||||
| Txn Hash | Age | Event | Topics / Data |
|---|---|---|---|
| no event logs emitted by this address | |||
| Transaction Hash | Method | Block | Age | From | To | Type | Item | ||
|---|---|---|---|---|---|---|---|---|---|
| no NFT transfers for this address yet | |||||||||
| Type | Age | Block | Details |
|---|---|---|---|
| no cross-chain L1↔L2 transactions for this address | |||
| Transaction Hash | Method | Block | Age | From | To | Amount | Token | ||
|---|---|---|---|---|---|---|---|---|---|
| 0x6d575e17…2bfecf | Transfer | 18,424,073 | 24 days agoFri, 24 Jul 2026 20:08:04 UTC | 0xcaf7…5d11 | IN | 0xf188…26cb | $0.001 DIH | ||
| 0xf811fb08…db0c72 | Transfer | 2,374,834 | 44 days agoSat, 04 Jul 2026 13:13:58 UTC | 0xe06f…6b43 | IN | 0xf188…26cb | 200,000,000.000000 TEST | test (TEST) |
| Block | Age | Parent Transaction Hash | Type | Method | From | To | Value | |
|---|---|---|---|---|---|---|---|---|
| 2,374,834 | 44 days agoSat, 04 Jul 2026 13:13:58 UTC | 0xf811fb…db0c72 | CREATE | createToken | 0xe06f…6b43 | IN | 0xf188…26cb | 0 ETH |