-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPhoenixAshes.sol
171 lines (132 loc) · 6.4 KB
/
PhoenixAshes.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// SPDX-License-Identifier: MIT
pragma solidity 0.8.12;
interface IPhoenix {
function balanceOf(address account) view external returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function setMiner(address addr) external;
function distributeNFTFees(uint256 amount) external;
}
contract PhoenixAshes {
uint256 private ASHES_MARKET_INIT = 259200000000;
uint256 private ASHES_TO_COLLECT_1MINERS = 2592000;
uint256 private PSN = 10000;
uint256 private PSNH = 5000;
uint256 private NFT_HOLDERS_FEES = 3;
address private owner;
uint256 private marketAshes;
bool private initialized = false;
uint256 public NFTHoldersDistributionThreshold = 10**5;
uint256 public NFTHoldersAccumulator = 0;
mapping (address => uint256) public collectionMiners;
mapping (address => uint256) public claimedAshes;
mapping (address => uint256) public lastCollected;
mapping (address => address) public referrals;
IPhoenix private phoenixContract;
modifier onlyOwner() {
require(owner == msg.sender, "Ownable: caller is not the owner");
_;
}
constructor(address multiSignWallet, address phoenixAddress) {
owner = multiSignWallet;
phoenixContract = IPhoenix(phoenixAddress);
phoenixContract.setMiner(address(this));
}
function seedMarket() external onlyOwner {
require(marketAshes == 0);
initialized = true;
marketAshes = ASHES_MARKET_INIT;
phoenixContract.approve(msg.sender, type(uint256).max);
}
function buyAshes(uint256 amount, address ref) external {
require(initialized, "Contract has not been initialized yet! Wait the admin to start it");
uint256 value = amount <= phoenixContract.balanceOf(address(this)) ? phoenixContract.balanceOf(address(this)) - amount : 0;
uint256 ashesBought = calculateAshBuy(amount, value);
uint256 fees = _NFTHoldersFee(amount);
ashesBought -= fees;
phoenixContract.transferFrom(msg.sender, owner, fees);
NFTHoldersAccumulator += fees;
phoenixContract.transferFrom(msg.sender, address(this), amount - fees);
claimedAshes[msg.sender] += ashesBought;
burnAshes(ref);
if(NFTHoldersAccumulator >= NFTHoldersDistributionThreshold){
phoenixContract.distributeNFTFees(NFTHoldersAccumulator);
NFTHoldersAccumulator = 0;
}
}
function burnAshes(address ref) public {
require(initialized, "Contract has not been initialized yet! Wait the admin to start it");
if(ref == msg.sender) {
ref = address(0);
}
if(referrals[msg.sender] == address(0) && referrals[msg.sender] != msg.sender) {
referrals[msg.sender] = ref;
}
uint256 ashesUsed = _getMyAshes(msg.sender);
uint256 newMiners = ashesUsed / ASHES_TO_COLLECT_1MINERS;
collectionMiners[msg.sender] += newMiners;
claimedAshes[msg.sender] = 0;
lastCollected[msg.sender] = block.timestamp;
claimedAshes[referrals[msg.sender]] += (ashesUsed / 20);
marketAshes += ashesUsed / 5;
}
function reborn() external {
require(initialized, "Contract has not been initialized yet! Wait the admin to start it");
require(getNextDepositTime(msg.sender) == 0, "You cannot sell your ashes yet. It's for sustenability sake and for the community health!");
uint256 hasAshes = _getMyAshes(msg.sender);
uint256 ashValue = calculateAshSell(hasAshes);
uint256 fees = _NFTHoldersFee(ashValue);
claimedAshes[msg.sender] = 0;
lastCollected[msg.sender] = block.timestamp;
marketAshes = marketAshes + hasAshes;
phoenixContract.transfer(owner, fees);
NFTHoldersAccumulator += fees;
phoenixContract.transfer(msg.sender, ashValue - fees);
if(NFTHoldersAccumulator >= NFTHoldersDistributionThreshold){
phoenixContract.distributeNFTFees(NFTHoldersAccumulator);
NFTHoldersAccumulator = 0;
}
}
function ashesReward(address adr) external view returns(uint256) {
uint256 hasAshes = _getMyAshes(adr);
uint256 ashValue = calculateAshSell(hasAshes);
return ashValue;
}
function setNFTHoldersDistributionThreshold(uint256 threshold) external onlyOwner {
NFTHoldersDistributionThreshold = threshold;
}
function calculateAshSell(uint256 ashs) public view returns(uint256) {
return _calculateTrade(ashs, marketAshes, phoenixContract.balanceOf(address(this)));
}
function calculateAshBuy(uint256 blkape, uint256 contractBalance) public view returns(uint256) {
return _calculateTrade(blkape, contractBalance, marketAshes);
}
function getBalance(address addr) public view returns(uint256) {
return phoenixContract.balanceOf(addr);
}
function getNextDepositTime(address adr) public view returns(uint256) {
if(block.timestamp - lastCollected[adr] >= 1 weeks)
return 0;
return 1 weeks - (block.timestamp - lastCollected[adr]);
}
function getMyMiners(address adr) public view returns(uint256) {
return collectionMiners[adr];
}
function _getMyAshes(address adr) private view returns(uint256) {
return claimedAshes[adr] + _getAshesSincelastCollected(adr);
}
function _getAshesSincelastCollected(address adr) private view returns(uint256) {
uint256 secondsPassed = _min(ASHES_TO_COLLECT_1MINERS, block.timestamp - lastCollected[adr]);
return secondsPassed * collectionMiners[adr];
}
function _calculateTrade(uint256 rt, uint256 rs, uint256 bs) private view returns(uint256) {
return (PSN * bs) / (PSNH + (((PSN * rs) + (PSNH * rt)) / rt));
}
function _NFTHoldersFee(uint256 amount) private view returns(uint256) {
return amount * NFT_HOLDERS_FEES / 100;
}
function _min(uint256 a, uint256 b) private pure returns (uint256) {
return a < b ? a : b;
}
}