Secure Smart Contract library providing battle-tested implementations of industry-standard Solidity contracts including ERC20, ERC721, ERC1155 tokens, access control mechanisms, proxy patterns, and governance systems for Ethereum and EVM-compatible blockchains.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
OpenZeppelin Contracts provides essential financial mechanisms for handling cryptocurrency payments, distributions, and vesting schedules in smart contracts.
Import financial contracts using Solidity import statements:
import "@openzeppelin/contracts/finance/PaymentSplitter.sol";
import "@openzeppelin/contracts/finance/VestingWallet.sol";Splits incoming payments among multiple payees according to their share allocation. Supports both Ether and ERC20 token distributions.
contract PaymentSplitter is Context {
constructor(address[] memory payees, uint256[] memory shares_);
function totalShares() public view returns (uint256);
function totalReleased() public view returns (uint256);
function totalReleased(IERC20 token) public view returns (uint256);
function shares(address account) public view returns (uint256);
function released(address account) public view returns (uint256);
function released(IERC20 token, address account) public view returns (uint256);
function payee(uint256 index) public view returns (address);
function releasable(address account) public view returns (uint256);
function releasable(IERC20 token, address account) public view returns (uint256);
function release(address payable account) public virtual;
function release(IERC20 token, address account) public virtual;
}event PayeeAdded(address account, uint256 shares);
event PaymentReleased(address to, uint256 amount);
event ERC20PaymentReleased(IERC20 indexed token, address to, uint256 amount);
event PaymentReceived(address from, uint256 amount);pragma solidity ^0.8.0;
import "@openzeppelin/contracts/finance/PaymentSplitter.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract RevenueSharing is PaymentSplitter {
constructor(
address[] memory founders,
uint256[] memory founderShares
) PaymentSplitter(founders, founderShares) {}
// Contract automatically receives and splits payments
receive() external payable {
// PaymentSplitter handles the payment tracking
}
function releaseAll() external {
for (uint256 i = 0; i < payee(i) != address(0); i++) {
address payeeAddress = payee(i);
if (releasable(payeeAddress) > 0) {
release(payable(payeeAddress));
}
}
}
function releaseToken(IERC20 token) external {
for (uint256 i = 0; i < payee(i) != address(0); i++) {
address payeeAddress = payee(i);
if (releasable(token, payeeAddress) > 0) {
release(token, payeeAddress);
}
}
}
}Implements token vesting functionality with linear release schedules over a specified duration.
contract VestingWallet is Context {
constructor(address beneficiaryAddress, uint64 startTimestamp, uint64 durationSeconds);
function beneficiary() public view virtual returns (address);
function start() public view virtual returns (uint256);
function duration() public view virtual returns (uint256);
function released() public view virtual returns (uint256);
function released(address token) public view virtual returns (uint256);
function releasable() public view virtual returns (uint256);
function releasable(address token) public view virtual returns (uint256);
function release() public virtual;
function release(address token) public virtual;
function vestedAmount(uint64 timestamp) public view virtual returns (uint256);
function vestedAmount(address token, uint64 timestamp) public view virtual returns (uint256);
}event EtherReleased(uint256 amount);
event ERC20Released(address indexed token, uint256 amount);pragma solidity ^0.8.0;
import "@openzeppelin/contracts/finance/VestingWallet.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract TeamVesting {
mapping(address => VestingWallet) public vestingWallets;
IERC20 public token;
constructor(IERC20 _token) {
token = _token;
}
function createVestingSchedule(
address beneficiary,
uint256 amount,
uint64 startTime,
uint64 duration
) external {
// Create vesting wallet for team member
VestingWallet vestingWallet = new VestingWallet(
beneficiary,
startTime,
duration
);
vestingWallets[beneficiary] = vestingWallet;
// Transfer tokens to vesting wallet
token.transfer(address(vestingWallet), amount);
}
function releaseVestedTokens(address beneficiary) external {
VestingWallet wallet = vestingWallets[beneficiary];
require(address(wallet) != address(0), "No vesting schedule");
wallet.release(address(token));
}
function getVestingInfo(address beneficiary)
external
view
returns (
uint256 totalAmount,
uint256 releasedAmount,
uint256 releasableAmount,
uint256 startTime,
uint256 duration
)
{
VestingWallet wallet = vestingWallets[beneficiary];
require(address(wallet) != address(0), "No vesting schedule");
totalAmount = token.balanceOf(address(wallet)) + wallet.released(address(token));
releasedAmount = wallet.released(address(token));
releasableAmount = wallet.releasable(address(token));
startTime = wallet.start();
duration = wallet.duration();
}
}pragma solidity ^0.8.0;
import "@openzeppelin/contracts/finance/PaymentSplitter.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract EscrowPaymentSplitter is PaymentSplitter, ReentrancyGuard {
enum EscrowState { Pending, Released, Disputed }
struct Escrow {
uint256 amount;
EscrowState state;
uint256 releaseTime;
}
mapping(bytes32 => Escrow) public escrows;
address public arbiter;
constructor(
address[] memory payees,
uint256[] memory shares_,
address _arbiter
) PaymentSplitter(payees, shares_) {
arbiter = _arbiter;
}
function createEscrow(bytes32 escrowId, uint256 releaseTime) external payable {
require(escrows[escrowId].amount == 0, "Escrow already exists");
require(msg.value > 0, "Must send funds");
escrows[escrowId] = Escrow({
amount: msg.value,
state: EscrowState.Pending,
releaseTime: releaseTime
});
}
function releaseEscrow(bytes32 escrowId) external nonReentrant {
Escrow storage escrow = escrows[escrowId];
require(escrow.state == EscrowState.Pending, "Escrow not pending");
require(block.timestamp >= escrow.releaseTime, "Release time not reached");
escrow.state = EscrowState.Released;
// Funds automatically split according to PaymentSplitter shares
(bool success, ) = address(this).call{value: escrow.amount}("");
require(success, "Failed to release funds");
}
}pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MilestoneVesting is Ownable {
struct Milestone {
uint256 amount;
bool completed;
bool released;
}
struct VestingSchedule {
address beneficiary;
uint256 totalAmount;
uint256 releasedAmount;
Milestone[] milestones;
}
mapping(address => VestingSchedule) public vestingSchedules;
IERC20 public token;
event MilestoneCompleted(address indexed beneficiary, uint256 milestoneIndex);
event TokensReleased(address indexed beneficiary, uint256 amount);
constructor(IERC20 _token) {
token = _token;
}
function createVestingSchedule(
address beneficiary,
uint256[] memory milestoneAmounts
) external onlyOwner {
require(vestingSchedules[beneficiary].beneficiary == address(0), "Schedule exists");
VestingSchedule storage schedule = vestingSchedules[beneficiary];
schedule.beneficiary = beneficiary;
uint256 totalAmount = 0;
for (uint256 i = 0; i < milestoneAmounts.length; i++) {
schedule.milestones.push(Milestone({
amount: milestoneAmounts[i],
completed: false,
released: false
}));
totalAmount += milestoneAmounts[i];
}
schedule.totalAmount = totalAmount;
token.transferFrom(msg.sender, address(this), totalAmount);
}
function completeMilestone(address beneficiary, uint256 milestoneIndex) external onlyOwner {
VestingSchedule storage schedule = vestingSchedules[beneficiary];
require(schedule.beneficiary != address(0), "No vesting schedule");
require(milestoneIndex < schedule.milestones.length, "Invalid milestone");
require(!schedule.milestones[milestoneIndex].completed, "Already completed");
schedule.milestones[milestoneIndex].completed = true;
emit MilestoneCompleted(beneficiary, milestoneIndex);
}
function releaseMilestone(uint256 milestoneIndex) external {
VestingSchedule storage schedule = vestingSchedules[msg.sender];
require(schedule.beneficiary == msg.sender, "Not beneficiary");
require(milestoneIndex < schedule.milestones.length, "Invalid milestone");
Milestone storage milestone = schedule.milestones[milestoneIndex];
require(milestone.completed, "Milestone not completed");
require(!milestone.released, "Already released");
milestone.released = true;
schedule.releasedAmount += milestone.amount;
token.transfer(msg.sender, milestone.amount);
emit TokensReleased(msg.sender, milestone.amount);
}
}// Combine vesting with governance tokens
contract GovernanceVesting is VestingWallet {
constructor(
address beneficiary,
uint64 startTimestamp,
uint64 durationSeconds
) VestingWallet(beneficiary, startTimestamp, durationSeconds) {}
// Override to delegate voting power while tokens are vesting
function _afterTokenTransfer(address token, uint256 amount) internal {
// Delegate voting power to beneficiary even while tokens are locked
IVotes(token).delegate(beneficiary());
}
}// Multi-signature controlled payment splitter
contract MultiSigPaymentSplitter is PaymentSplitter, AccessControl {
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
modifier onlyAdmin() {
require(hasRole(ADMIN_ROLE, msg.sender), "Not admin");
_;
}
function emergencyWithdraw(address token, uint256 amount) external onlyAdmin {
// Emergency withdrawal mechanism
}
}Financial contracts may revert with various errors:
PaymentSplitter__InvalidShares(), PaymentSplitter__NoPayeesProvided()Install with Tessl CLI
npx tessl i tessl/npm-openzeppelin-solidity