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
21 changes: 21 additions & 0 deletions Projects/ERC1155.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// contracts/GameItems.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";

contract GameItems is ERC1155 {
uint256 public constant GOLD = 0;
uint256 public constant SILVER = 1;
uint256 public constant THORS_HAMMER = 2;
uint256 public constant SWORD = 3;
uint256 public constant SHIELD = 4;

constructor() ERC1155("https://game.example/api/item/{id}.json") {
_mint(msg.sender, GOLD, 10 ** 18, "");
_mint(msg.sender, SILVER, 10 ** 27, "");
_mint(msg.sender, THORS_HAMMER, 1, "");
_mint(msg.sender, SWORD, 10 ** 9, "");
_mint(msg.sender, SHIELD, 10 ** 9, "");
}
}
21 changes: 21 additions & 0 deletions Projects/ERC20.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.6.0
pragma solidity ^0.8.27;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";

contract MyToken is ERC20, Ownable, ERC20Permit {
constructor(address recipient, address initialOwner)
ERC20("MyToken", "MTK")
Ownable(initialOwner)
ERC20Permit("MyToken")
{
_mint(recipient, 100000 * 10 ** decimals());
}

function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
}
99 changes: 99 additions & 0 deletions Projects/ERC20Staking
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.6.0
pragma solidity ^0.8.27;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";

разделить логику
 – initialize() — базовая инициализация
 – startVesting() — запуск вестинга (только после пополнения контракта

contract ERC20Staking is Ownable {

function initialize(address[] memory _beneficiary, uint256 _totalAmount, uint256 _cliff, uint256 _startTime, uint256 _endTime, uint256 _minimalAmountToClaim) public {
struct Staking {
address beneficiary;
uint256 totalAmount;
uint256 cliff;
uint256 startTime;
uint256 endTime;
uint256 minimalAmountToClaim;
}
beneficiary = _beneficiary;
totalAmount = _totalAmount;
cliff = _cliff;
startTime = _startTime;
endTime = _endTime;
minimalAmountToClaim = _minimalAmountToClaim;

modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}

}
function startVesting(address[] memory _beneficiary, uint256 _totalAmount, uint256 _cliff, uint256 _startTime, uint256 _endTime, uint256 _minimalAmountToClaim) external, onlyOwner() {
struct Staking {
address beneficiary = _beneficiary;
uint256 totalAmount = _totalAmount;
uint256 cliff = _cliff;
uint256 startTime = _startTime;
uint256 endTime = _endTime;
uint256 minimalAmountToClaim = _minimalAmountToClaim;
}
}
constructor(address _beneficiary, uint256 _totalAmount, uint256 _cliff, uint256 _startTime, uint256 _endTime, uint256 _minimalAmountToClaim) Ownable(msg.sender) {
beneficiary = _beneficiary;
totalAmount = _totalAmount;
cliff = _cliff;
startTime = _startTime;
endTime = _endTime;
minimalAmountToClaim = _minimalAmountToClaim;
}

function claim(uint256 _amount) public {

если юыло заклеймлено то пояаляетмя таймер до возможности заклеймить еще
таймер возможности заклеймить в днях

Добавить поддержку нескольких получателей

маппинги стракты

mapping (address(benefeciary) => struct )






uint256 timer = block.timestamp + 1 days
if CoolDownTimer > 0 ,error timerNotEnded

if msg.sender != beneficiary, error not beneficiary
if block.timestamp < startTime, error rano start ne nastupil
if block.timestamp < cliff, error rano cliff ne nastupil
if block.timestamp >= endTime ,error claimTimeEnded

uint256 amountToClaim = (totalAmount * (block.timestamp - (startTime + cliff))) / Duration;
if amountToClaim < minimalAmountToClaim, error not enough amount to claim
if amountToClaim > amount , error overmnoga
amount -= amountToClaim
claimed += amountToClaim
require(ERC20(token).transfer(benefeciary, amountToClaim))
CoolDownTimer = block.timestamp + 1 day


emit Claimed(amountToClaim)
emit CoolDownTimerSet(CoolDownTimer)


}





}
150 changes: 150 additions & 0 deletions Projects/ERC20stakingg
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.6.0
pragma solidity ^0.8.27;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract ERC20Staking is Ownable {
struct Staking {
uint256 totalAmount;
uint256 claimed;
uint64 startTime;
uint64 endTime;
uint64 cliff;
uint64 minimalAmountToClaim;
uint64 cooldownEndsAt;
}

/// @notice Vesting data per beneficiary
mapping(address => Staking) public stakes;

/// @notice ERC20 token used for payouts
IERC20 public token;

/// @notice Global vesting schedule parameters (shared by all beneficiaries)
uint64 public globalStartTime;
uint64 public globalEndTime;
uint64 public globalCliff;
uint64 public globalMinimalAmountToClaim;

/// @notice Cooldown duration (in seconds) after each claim
uint64 public cooldownDuration;

/// @notice Total amount allocated across all beneficiaries
uint256 public totalAllocated;

event VestingStarted(address indexed beneficiary, uint256 amount);
event Claimed(address indexed beneficiary, uint256 amount);
event CooldownSet(address indexed beneficiary, uint64 until);

constructor(
address token_,
uint64 startTime_,
uint64 endTime_,
uint64 cliff_,
uint64 minimalAmountToClaim_,
uint64 cooldownDuration_
) Ownable(msg.sender) {
require(token_ != address(0), "Token is zero");
require(startTime_ < endTime_, "Invalid time range");
require(cliff_ >= startTime_, "Cliff before start");

token = IERC20(token_);
globalStartTime = startTime_;
globalEndTime = endTime_;
globalCliff = cliff_;
globalMinimalAmountToClaim = minimalAmountToClaim_;
cooldownDuration = cooldownDuration_;
}

/// @notice Fill or extend vesting stakes for multiple beneficiaries.
/// @dev Assumes the contract is already funded with enough tokens.
function startVesting(
address[] calldata beneficiaries,
uint256[] calldata amounts
) external onlyOwner {
uint256 length = beneficiaries.length;
require(length == amounts.length && length > 0, "Invalid input");

uint256 addedTotal;

for (uint256 i = 0; i < length; i++) {
address beneficiary = beneficiaries[i];
uint256 amount = amounts[i];

require(beneficiary != address(0), "Zero beneficiary");
require(amount > 0, "Zero amount");

Staking storage s = stakes[beneficiary];

// First time configuration for this beneficiary
if (s.totalAmount == 0 && s.claimed == 0) {
s.startTime = globalStartTime;
s.endTime = globalEndTime;
s.cliff = globalCliff;
s.minimalAmountToClaim = globalMinimalAmountToClaim;
} else {
// Ensure that all schedules remain aligned with the global one
require(
s.startTime == globalStartTime &&
s.endTime == globalEndTime &&
s.cliff == globalCliff &&
s.minimalAmountToClaim == globalMinimalAmountToClaim,
"Schedule mismatch"
);
}

s.totalAmount += amount;
addedTotal += amount;

emit VestingStarted(beneficiary, amount);
}

totalAllocated += addedTotal;
require(totalAllocated <= token.balanceOf(address(this)), "Insufficient pool");
}

/// @notice Claim vested tokens for the caller.
/// @param requestedAmount If 0, claims full available amount, otherwise
/// claims the minimum of requestedAmount and the currently claimable amount.
function claim(uint256 requestedAmount) external {
Staking storage s = stakes[msg.sender];

require(s.totalAmount > 0, "No vesting");
require(block.timestamp >= s.startTime, "Vesting not started");
require(block.timestamp >= s.cliff, "Cliff not reached");
require(block.timestamp < s.endTime, "Vesting ended");
require(block.timestamp >= s.cooldownEndsAt, "Cooldown active");

uint256 duration = uint256(s.endTime) - uint256(s.startTime);
require(duration > 0, "Invalid duration");

uint256 timePassed = block.timestamp - uint256(s.startTime);
if (timePassed > duration) {
timePassed = duration;
}

uint256 vestedTotal = (s.totalAmount * timePassed) / duration;

if (vestedTotal <= s.claimed) {
revert("Nothing to claim");
}

uint256 claimable = vestedTotal - s.claimed;
require(claimable >= s.minimalAmountToClaim, "Too small");

uint256 claimAmount = claimable;
if (requestedAmount > 0 && requestedAmount < claimable) {
claimAmount = requestedAmount;
}

s.claimed += claimAmount;
s.cooldownEndsAt = uint64(block.timestamp + cooldownDuration);

require(token.transfer(msg.sender, claimAmount), "Transfer failed");

emit Claimed(msg.sender, claimAmount);
emit CooldownSet(msg.sender, s.cooldownEndsAt);
}
}
19 changes: 19 additions & 0 deletions Projects/ERC721.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// contracts/GameItem.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {ERC721URIStorage, ERC721} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";

contract Frameitem is ERC721URIStorage {
uint256 private _nextTokenId;

constructor() ERC721("Frameitem", "FRI") {}

function awardItem(address player, string memory tokenURI) public returns (uint256) {
uint256 tokenId = _nextTokenId++;
_mint(player, tokenId);
_setTokenURI(tokenId, tokenURI);

return tokenId;
}
}