Skip to content

Commit d7fbc0d

Browse files
committed
feat: /LimitedMintingWETH.sol #737
1 parent f7019d0 commit d7fbc0d

File tree

1 file changed

+186
-0
lines changed

1 file changed

+186
-0
lines changed

testnet/LimitedMintingWETH.sol

+186
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.25;
3+
4+
// Zaros dependencies
5+
import { IPerpsEngine } from "@zaros/perpetuals/PerpsEngine.sol";
6+
7+
// Open zeppelin upgradeable dependencies
8+
import { ERC20PermitUpgradeable } from "@openzeppelin-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol";
9+
import { OwnableUpgradeable } from "@openzeppelin-upgradeable/access/OwnableUpgradeable.sol";
10+
import { UUPSUpgradeable } from "@openzeppelin-upgradeable/proxy/utils/UUPSUpgradeable.sol";
11+
import { IERC721Enumerable } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
12+
13+
// PRB Math dependencies
14+
import { UD60x18 } from "@prb-math/UD60x18.sol";
15+
import { SD59x18 } from "@prb-math/SD59x18.sol";
16+
17+
/// @notice LimitedMintingERC20 is an ERC20 token with limited minting capabilities used in testnet.
18+
contract LimitedMintingERC20 is UUPSUpgradeable, ERC20PermitUpgradeable, OwnableUpgradeable {
19+
/*//////////////////////////////////////////////////////////////////////////
20+
VARIABLES FUNCTIONS
21+
//////////////////////////////////////////////////////////////////////////*/
22+
23+
/// @notice Address of the Perpetuals Engine contract.
24+
address public constant PERPS_ENGINE = 0x6f7b7e54a643E1285004AaCA95f3B2e6F5bcC1f3;
25+
26+
/// @notice Amount of tokens minted per address.
27+
uint256 public constant AMOUNT_TO_MINT_WETH = 1 * 10 ** 18;
28+
29+
uint256 public constant MAX_AMOUNT_USER_SHOULD_HAVE_BEFORE_THE_MINT = 0.1 * 10 ** 18;
30+
31+
/// @notice Start time for minting.
32+
uint256 public startTimeMinting;
33+
34+
/// @notice Mapping of the amount minted per address.
35+
mapping(address user => uint256 amount) public amountMintedPerAddress;
36+
37+
/// @notice Mapping of the last minted time per address.
38+
mapping(address user => uint256 lastMintedTime) public userLastMintedTime;
39+
40+
/// @notice Mapping of the user already minted free remint.
41+
mapping(address user => bool alreadyMinted) public userAlreadyMintedFreeRemint;
42+
43+
/// @notice Mapping of the user already minted the secondig round of free remint.
44+
mapping(address user => bool alreadyMinted) public userAlreadyMintedTheSecondRoundFreeRemint;
45+
46+
/*//////////////////////////////////////////////////////////////////////////
47+
ERRORS FUNCTIONS
48+
//////////////////////////////////////////////////////////////////////////*/
49+
50+
/// @notice Error emitted when the amount to mint is zero.
51+
error LimitedMintingERC20_ZeroAmount();
52+
53+
/// @notice Error emitted when the user is not permitted.
54+
error LimitedMintingERC20_UserIsNotPermitted(address user);
55+
56+
/// @notice Error emitted when minting is not started.
57+
error LimitedMintingERC20_MintingIsNotStarted(uint256 timestampStartDate);
58+
59+
/// @notice Error emitted when the user has already minted this week.
60+
error LimitedMintingERC20_UserAlreadyMintedThisWeek(address user, uint256 lastMintedTime);
61+
62+
/// @notice Error emitted when the user has more than the maximum amount.
63+
error LimitedMintingERC20_UserHasMoreThanMaxAmount(address user, uint256 amount, uint256 maxAmount);
64+
65+
/*//////////////////////////////////////////////////////////////////////////
66+
INITIALIZE FUNCTIONS
67+
//////////////////////////////////////////////////////////////////////////*/
68+
69+
function initialize(address owner, string memory name, string memory symbol) external initializer {
70+
__ERC20_init(name, symbol);
71+
__ERC20Permit_init(name);
72+
__Ownable_init(owner);
73+
}
74+
75+
/*//////////////////////////////////////////////////////////////////////////
76+
PUBLIC FUNCTIONS
77+
//////////////////////////////////////////////////////////////////////////*/
78+
79+
function transfer(address to, uint256 value) public virtual override returns (bool) {
80+
if (msg.sender != PERPS_ENGINE) {
81+
revert LimitedMintingERC20_UserIsNotPermitted(msg.sender);
82+
}
83+
84+
return super.transfer(to, value);
85+
}
86+
87+
function transferFrom(address from, address to, uint256 value) public virtual override returns (bool) {
88+
if (msg.sender != PERPS_ENGINE) {
89+
revert LimitedMintingERC20_UserIsNotPermitted(msg.sender);
90+
}
91+
92+
return super.transferFrom(from, to, value);
93+
}
94+
95+
function verifyIfUserIsEnableToMint(uint256 tokenIndex, bool shouldRevert) public view returns (bool isEnabled) {
96+
if (block.timestamp < startTimeMinting) {
97+
if (shouldRevert) {
98+
revert LimitedMintingERC20_MintingIsNotStarted(startTimeMinting);
99+
} else {
100+
return isEnabled;
101+
}
102+
}
103+
104+
if (!userAlreadyMintedTheSecondRoundFreeRemint[msg.sender]) {
105+
isEnabled = true;
106+
return isEnabled;
107+
}
108+
109+
uint256 numberOfWeeks = (block.timestamp - startTimeMinting) / 7 days;
110+
111+
if (userLastMintedTime[msg.sender] >= startTimeMinting + numberOfWeeks * 7 days) {
112+
if (shouldRevert) {
113+
revert LimitedMintingERC20_UserAlreadyMintedThisWeek(msg.sender, userLastMintedTime[msg.sender]);
114+
} else {
115+
return isEnabled;
116+
}
117+
}
118+
119+
uint256 userBalance = balanceOf(msg.sender);
120+
address tradingAccountToken = IPerpsEngine(PERPS_ENGINE).getTradingAccountToken();
121+
bool userHasTradingAccount = IERC721Enumerable(tradingAccountToken).balanceOf(msg.sender) > 0;
122+
123+
if (userHasTradingAccount) {
124+
uint128 tradingAccountId = uint128(IERC721Enumerable(tradingAccountToken).tokenOfOwnerByIndex(msg.sender, tokenIndex));
125+
(SD59x18 marginBalanceUsdX18,,,) = IPerpsEngine(PERPS_ENGINE).getAccountMarginBreakdown(tradingAccountId);
126+
127+
userBalance += uint256(marginBalanceUsdX18.intoInt256());
128+
}
129+
130+
if (userLastMintedTime[msg.sender] > 0 && userBalance > MAX_AMOUNT_USER_SHOULD_HAVE_BEFORE_THE_MINT) {
131+
if (shouldRevert) {
132+
revert LimitedMintingERC20_UserHasMoreThanMaxAmount(
133+
msg.sender, userBalance, MAX_AMOUNT_USER_SHOULD_HAVE_BEFORE_THE_MINT
134+
);
135+
} else {
136+
return isEnabled;
137+
}
138+
}
139+
140+
isEnabled = true;
141+
}
142+
143+
/*//////////////////////////////////////////////////////////////////////////
144+
EXTERNAL FUNCTIONS
145+
//////////////////////////////////////////////////////////////////////////*/
146+
147+
function setStartTimeMinting(uint256 _startTimeMinting) external onlyOwner {
148+
startTimeMinting = _startTimeMinting;
149+
}
150+
151+
function mint(address to, uint256 amount) external onlyOwner {
152+
_mint(to, amount);
153+
}
154+
155+
function mint(uint256 tokenIndex) external {
156+
verifyIfUserIsEnableToMint(tokenIndex, true);
157+
158+
userLastMintedTime[msg.sender] = block.timestamp;
159+
amountMintedPerAddress[msg.sender] = AMOUNT_TO_MINT_WETH;
160+
161+
if(!userAlreadyMintedTheSecondRoundFreeRemint[msg.sender]) {
162+
userAlreadyMintedTheSecondRoundFreeRemint[msg.sender] = true;
163+
}
164+
165+
_mint(msg.sender, AMOUNT_TO_MINT_WETH);
166+
}
167+
168+
function burn(address from, uint256 amount) external {
169+
_requireAmountNotZero(amount);
170+
_burn(from, amount);
171+
}
172+
173+
/*//////////////////////////////////////////////////////////////////////////
174+
PRIVATE FUNCTIONS
175+
//////////////////////////////////////////////////////////////////////////*/
176+
177+
function _requireAmountNotZero(uint256 amount) private pure {
178+
if (amount == 0) revert LimitedMintingERC20_ZeroAmount();
179+
}
180+
181+
/*//////////////////////////////////////////////////////////////////////////
182+
INTERNAL FUNCTIONS
183+
//////////////////////////////////////////////////////////////////////////*/
184+
185+
function _authorizeUpgrade(address) internal override onlyOwner { }
186+
}

0 commit comments

Comments
 (0)