Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 25 from a total of 85 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Claim | 20423616 | 588 days ago | IN | 0 ETH | 0.00027701 | ||||
| Claim | 20395545 | 592 days ago | IN | 0 ETH | 0.0000895 | ||||
| Claim | 20300197 | 606 days ago | IN | 0 ETH | 0.00014895 | ||||
| Claim | 20228918 | 616 days ago | IN | 0 ETH | 0.00055196 | ||||
| Claim | 20136820 | 628 days ago | IN | 0 ETH | 0.00021431 | ||||
| Claim | 20108282 | 632 days ago | IN | 0 ETH | 0.00029195 | ||||
| Claim | 20084414 | 636 days ago | IN | 0 ETH | 0.00091788 | ||||
| Claim | 20036548 | 642 days ago | IN | 0 ETH | 0.00076446 | ||||
| Claim | 19984441 | 650 days ago | IN | 0 ETH | 0.00119736 | ||||
| Claim | 19956628 | 654 days ago | IN | 0 ETH | 0.00042708 | ||||
| Claim | 19924667 | 658 days ago | IN | 0 ETH | 0.00050248 | ||||
| Claim | 19914165 | 660 days ago | IN | 0 ETH | 0.0019464 | ||||
| Claim | 19891612 | 663 days ago | IN | 0 ETH | 0.00032871 | ||||
| Claim | 19821596 | 673 days ago | IN | 0 ETH | 0.00033014 | ||||
| Claim | 19808863 | 674 days ago | IN | 0 ETH | 0.00032835 | ||||
| Claim | 19792199 | 677 days ago | IN | 0 ETH | 0.0005009 | ||||
| Claim | 19782147 | 678 days ago | IN | 0 ETH | 0.00049527 | ||||
| Claim | 19754915 | 682 days ago | IN | 0 ETH | 0.00071505 | ||||
| Claim | 19743305 | 683 days ago | IN | 0 ETH | 0.00043704 | ||||
| Claim | 19728726 | 686 days ago | IN | 0 ETH | 0.0006539 | ||||
| Claim | 19701021 | 689 days ago | IN | 0 ETH | 0.00049227 | ||||
| Claim | 19687727 | 691 days ago | IN | 0 ETH | 0.00063545 | ||||
| Claim | 19649590 | 697 days ago | IN | 0 ETH | 0.00830194 | ||||
| Claim | 19588989 | 705 days ago | IN | 0 ETH | 0.0011735 | ||||
| Claim | 19493187 | 719 days ago | IN | 0 ETH | 0.00150873 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x3d602d80 | 17791361 | 957 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Minimal Proxy Contract for 0x80429330c476857bafddf61772bfe1263d765a1f
Contract Name:
Vesting
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.13;
import {IERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {IVesting} from "src/interfaces/IVesting.sol";
import {IVestingFactory} from "src/interfaces/IVestingFactory.sol";
/*//////////////////////////////////////////////////////////////
CUSTOM ERROR
//////////////////////////////////////////////////////////////*/
error NotInitialised();
error Initialised();
error NoAccess();
error ZeroAddress();
error NoVestingData();
error StartLessThanNow();
error ZeroAmount();
error ZeroClaimAmount();
error AlreadyClaimed();
error AlreadyCancelled();
error Uncancellable();
error SameRecipient();
/*//////////////////////////////////////////////////////////////
CONTRACT
//////////////////////////////////////////////////////////////*/
/// @title Vesting Contract
contract Vesting is IVesting {
// The recipient of the tokens
address public recipient;
uint40 public start;
uint40 public duration;
uint256 public amount;
// Total amount of tokens which are claimed
uint256 public totalClaimedAmount;
// Flag for whether the vesting is cancellable or not
bool public isCancellable;
// Flag for whether the vesting is cancelled or not
bool public cancelled;
// Flag to check if its initialised
bool private initialised;
IVestingFactory public factory;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
function initialise(address _recipient, uint40 _start, uint40 _duration, uint256 _amount, bool _isCancellable)
external
override
{
if (initialised) revert Initialised();
initialised = true;
recipient = _recipient;
start = _start;
duration = _duration;
amount = _amount;
isCancellable = _isCancellable;
factory = IVestingFactory(msg.sender);
}
/*//////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////*/
modifier onlyTreasury() {
if (msg.sender != factory.treasury()) revert NoAccess();
_;
}
modifier onlyOwner() {
bool isOwner;
if (isCancellable == false) {
// If the vest is uncancellable, only the recipient can call the function
isOwner = (msg.sender == recipient);
} else {
// If the vest is cancellable, only the treasury or the recipient can call the function
isOwner = (msg.sender == recipient) || (msg.sender == factory.treasury());
}
if (!isOwner) revert NoAccess();
_;
}
modifier onlyInit() {
if (!initialised) revert NotInitialised();
_;
}
/*//////////////////////////////////////////////////////////////
VIEW FUNCTIONS
//////////////////////////////////////////////////////////////*/
/// @notice Calculates the amount of tokens which have been accrued to date.
/// @notice This does not take into account the amount which has been claimed already.
/// @return uint256 The amount of tokens which have been accrued to date.
function getAccruedTokens() public view returns (uint256) {
if (block.timestamp >= start + duration) {
return amount;
} else if (block.timestamp < start) {
// Allows us to set up vests in advance
return 0;
} else {
return (block.timestamp - start) * (amount / duration);
}
}
/// @notice Calculates the amount of tokens which can be claimed.
/// @return uint256 The amount of tokens which can be claimed.
function getClaimableTokens() public view returns (uint256) {
if (cancelled) {
return 0;
}
uint256 accruedTokens = getAccruedTokens();
// Calculate the amount of tokens which can be claimed
uint256 tokensToClaim = accruedTokens - totalClaimedAmount;
return tokensToClaim;
}
/// @notice Gets the vesting details of the contract.
function getVestingDetails() public view returns (uint40, uint40, uint256, uint256, bool) {
return (start, duration, amount, totalClaimedAmount, isCancellable);
}
function getTokens() public view returns (uint256) {
// Assumes that the token has 18 decimals
return amount / (10 ** 18);
}
/*//////////////////////////////////////////////////////////////
EXTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////*/
/// @notice Changes the recipient of vested tokens.
/// @notice The old recipient will not be able to claim the tokens, the new recipient will be able to claim all unclaimed tokens accrued to date.
/// @dev Can be called by the treasury or the recipient depending on whether the vest is cancellable or not.
/// @param _newRecipient Address of the new recipient recieving the vested tokens.
function changeRecipient(address _newRecipient) external onlyOwner onlyInit {
if (_newRecipient == address(0)) revert ZeroAddress();
if (_newRecipient == recipient) revert SameRecipient();
if (start == 0) revert NoVestingData();
if (cancelled) revert AlreadyCancelled();
factory.changeRecipient(recipient, _newRecipient);
recipient = _newRecipient;
}
/// @notice Cancels the vest and transfers the accrued amount to the recipient.
/// @dev Can only be called by the treasury.
function cancelVest() external onlyTreasury onlyInit {
if (start < 1) revert NoVestingData();
if (isCancellable == false) revert Uncancellable();
if (cancelled) revert AlreadyCancelled();
uint256 claimAmount = getClaimableTokens();
if (claimAmount > 0) {
totalClaimedAmount += claimAmount;
factory.token().transfer(recipient, claimAmount);
}
cancelled = true;
// Transfer the remainder of the tokens to the treasury
factory.token().transfer(factory.treasury(), amount - totalClaimedAmount);
}
/// @notice A function allowing the recipient to claim the vested tokens.
/// @notice The function returns unclaimed tokens to the treasury.
/// @dev This function can be called by anyone.
function claim() public override onlyInit {
if (totalClaimedAmount >= amount) revert AlreadyClaimed();
if (cancelled) revert AlreadyCancelled();
uint256 claimAmount = getClaimableTokens();
if (claimAmount < 1) revert ZeroClaimAmount();
totalClaimedAmount += claimAmount;
factory.token().transfer(recipient, claimAmount);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.0;
interface IVesting {
function cancelled() external returns (bool);
function totalClaimedAmount() external returns (uint256);
function amount() external returns (uint256);
function initialise(address _recipient, uint40 _start, uint40 _duration, uint256 _amount, bool _isCancellable)
external;
function claim() external;
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.0;
import {IERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
interface IVestingFactory {
function treasury() external returns (address);
function token() external returns (IERC20);
function changeRecipient(address _oldRecipient, address _newRecipient) external;
}{
"remappings": [
"ds-test/=lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"bytecodeHash": "ipfs"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"libraries": {}
}Contract ABI
API[{"inputs":[],"name":"AlreadyCancelled","type":"error"},{"inputs":[],"name":"AlreadyClaimed","type":"error"},{"inputs":[],"name":"Initialised","type":"error"},{"inputs":[],"name":"NoAccess","type":"error"},{"inputs":[],"name":"NoVestingData","type":"error"},{"inputs":[],"name":"NotInitialised","type":"error"},{"inputs":[],"name":"SameRecipient","type":"error"},{"inputs":[],"name":"Uncancellable","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroClaimAmount","type":"error"},{"inputs":[],"name":"amount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelVest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newRecipient","type":"address"}],"name":"changeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"duration","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract IVestingFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAccruedTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getClaimableTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVestingDetails","outputs":[{"internalType":"uint40","name":"","type":"uint40"},{"internalType":"uint40","name":"","type":"uint40"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint40","name":"_start","type":"uint40"},{"internalType":"uint40","name":"_duration","type":"uint40"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bool","name":"_isCancellable","type":"bool"}],"name":"initialise","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isCancellable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"recipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"start","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalClaimedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.