/
Property.sol
748 lines (665 loc) · 32.8 KB
/
Property.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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../libraries/Helper.sol";
import "../interfaces/IUniHelper.sol";
import "../interfaces/IVote.sol";
import "../interfaces/IStakingPool.sol";
import "../interfaces/IOwnablee.sol";
contract Property is ReentrancyGuard {
event AuditorProposalCreated(address indexed creator, address member, string title, string description);
event RewardFundProposalCreated(address indexed creator, address member, string title, string description);
event FilmBoardProposalCreated(address indexed creator, address member, string title, string description);
event FilmBoardMemberRemoved(address indexed caller, address member);
event PropertyProposalCreated(
address indexed creator, uint256 property, uint256 flag, string title, string description
);
struct ProProposal {
string title; // title
string description; // description
uint256 createTime; // created timestamp
uint256 approveTime; // approved timestamp
uint256 proposalID; // ID
uint256 value; // property
address creator; // creator address
Helper.Status status; // status
}
struct GovProposal {
string title; // title
string description; // description
uint256 createTime; // created timestamp
uint256 approveTime; // approved timestamp
uint256 proposalID; // ID
address value; // address
address creator; // creator address
Helper.Status status; // status
}
struct Agent {
address agent; // agent address
uint256 stakeAmount; // stake amount of agent proposal creator
}
address private immutable OWNABLE; // Ownablee contract address
address private immutable VOTE; // Vote contract address
address private immutable STAKING_POOL; // StakingPool contract address
address private immutable UNI_HELPER; // UniHelper contract address
address public DAO_FUND_REWARD; // address for sending the DAO rewards fund
uint256 public filmVotePeriod; // 0 - film vote period
uint256 public agentVotePeriod; // 1 - vote period for replacing auditor
uint256 public disputeGracePeriod; // 2 - grace period for replacing Auditor
uint256 public propertyVotePeriod; // 3 - vote period for updating properties
uint256 public lockPeriod; // 4 - lock period for staked VAB
uint256 public rewardRate; // 5 - day rewards rate => 0.0004%(1% = 1e8, 100% = 1e10)
uint256 public filmRewardClaimPeriod; // 6 - period when the auditor can submit the films reward results to be claimed
uint256 public maxAllowPeriod; // 7 - max allowed period for removing filmBoard member
uint256 public proposalFeeAmount; // 8 - USDC amount($100) studio should pay when create a proposal
uint256 public fundFeePercent; // 9 - percent(2% = 2*1e8) of fee on the amount raised
uint256 public minDepositAmount; // 10 - USDC min amount($50) that a customer can deposit to a film approved for funding
uint256 public maxDepositAmount; // 11 - USDC max amount($5000) that a customer can deposit to a film approved for funding
uint256 public maxMintFeePercent; // 12 - 10%(1% = 1e8, 100% = 1e10)
uint256 public minVoteCount; // 13 - 5 ppl(minium voter count for approving the proposal)
uint256 public minStakerCountPercent; // 14 - percent(5% = 5*1e8)
uint256 public availableVABAmount; // 15 - vab amount for replacing the auditor
uint256 public boardVotePeriod; // 16 - filmBoard vote period
uint256 public boardVoteWeight; // 17 - filmBoard member's vote weight
uint256 public rewardVotePeriod; // 18 - withdraw address setup for moving to V2
uint256 public subscriptionAmount; // 19 - user need to have an active subscription(pay $1 per month) for rent films.
uint256 public boardRewardRate; // 20 - 25%(1% = 1e8, 100% = 1e10) more reward rate for filmboard members
// uint256 public disputLimitAmount;
uint256[] private maxPropertyList;
uint256[] private minPropertyList;
uint256 public governanceProposalCount;
uint256[] private filmVotePeriodList; // 0
uint256[] private agentVotePeriodList; // 1
uint256[] private disputeGracePeriodList; // 2
uint256[] private propertyVotePeriodList; // 3
uint256[] private lockPeriodList; // 4
uint256[] private rewardRateList; // 5
uint256[] private filmRewardClaimPeriodList; // 6
uint256[] private maxAllowPeriodList; // 7
uint256[] private proposalFeeAmountList; // 8
uint256[] private fundFeePercentList; // 9
uint256[] private minDepositAmountList; // 10
uint256[] private maxDepositAmountList; // 11
uint256[] private maxMintFeePercentList; // 12
uint256[] private minVoteCountList; // 13
uint256[] private minStakerCountPercentList; // 14
uint256[] private availableVABAmountList; // 15
uint256[] private boardVotePeriodList; // 16
uint256[] private boardVoteWeightList; // 17
uint256[] private rewardVotePeriodList; // 18
uint256[] private subscriptionAmountList; // 19
uint256[] private boardRewardRateList; // 20
Agent[] private agentList; // for replacing auditor
address[] private rewardAddressList; // for adding v2 pool address
address[] private filmBoardCandidates; // filmBoard candidates and if isBoardWhitelist is true, become filmBoard member
address[] private filmBoardMembers; // filmBoard members
// flag=1 =>agent, 2=>board, 3=>reward
mapping(uint256 => mapping(address => uint256)) private isGovWhitelist; // (flag => (address => 0: no, 1: candiate, 2: member))
mapping(uint256 => mapping(uint256 => uint256)) private isPropertyWhitelist; // (flag => (property => 0: no, 1: candiate, 2: member))
mapping(uint256 => mapping(uint256 => GovProposal)) private govProposalInfo; // (flag => (index => Proposal))
mapping(uint256 => mapping(uint256 => ProProposal)) private proProposalInfo; // (flag => (index => Proposal))
mapping(uint256 => address[]) private allGovProposalInfo; // (flag => address array))
mapping(address => uint256) public userGovProposalCount; // (user => created governance-proposal count)
modifier onlyVote() {
require(msg.sender == VOTE, "caller is not the vote contract");
_;
}
modifier onlyDeployer() {
require(msg.sender == IOwnablee(OWNABLE).deployer(), "caller is not the deployer");
_;
}
modifier onlyStaker() {
require(IStakingPool(STAKING_POOL).getStakeAmount(msg.sender) != 0, "Not staker");
_;
}
modifier onlyMajor() {
require(IStakingPool(STAKING_POOL).getStakeAmount(msg.sender) >= availableVABAmount, "Not major");
_;
}
constructor(address _ownable, address _uniHelper, address _vote, address _staking) {
require(_ownable != address(0), "ownable: zero address");
OWNABLE = _ownable;
require(_uniHelper != address(0), "uniHelper: zero address");
UNI_HELPER = _uniHelper;
require(_vote != address(0), "vote: zero address");
VOTE = _vote;
require(_staking != address(0), "staking: zero address");
STAKING_POOL = _staking;
filmVotePeriod = 10 days;
boardVotePeriod = 14 days;
agentVotePeriod = 10 days;
disputeGracePeriod = 30 days;
propertyVotePeriod = 10 days;
rewardVotePeriod = 7 days;
lockPeriod = 30 days;
maxAllowPeriod = 90 days;
filmRewardClaimPeriod = 30 days;
boardVoteWeight = 30 * 1e8; // 30% (1% = 1e8)
rewardRate = 25 * 1e5; //40000; // 0.0004% (1% = 1e8, 100%=1e10) // 2500000(0.025%)
boardRewardRate = 25 * 1e8; // 25%
fundFeePercent = 2 * 1e8; // percent(2%)
maxMintFeePercent = 10 * 1e8; // 10%
minStakerCountPercent = 5 * 1e8; // 5%(1% = 1e8, 100%=1e10)
address usdcToken = IOwnablee(_ownable).USDC_TOKEN();
address vabToken = IOwnablee(_ownable).PAYOUT_TOKEN();
proposalFeeAmount = 20 * (10 ** IERC20Metadata(usdcToken).decimals()); // amount in cash(usd dollar - $20)
minDepositAmount = 50 * (10 ** IERC20Metadata(usdcToken).decimals()); // amount in cash(usd dollar - $50)
maxDepositAmount = 5000 * (10 ** IERC20Metadata(usdcToken).decimals()); // amount in cash(usd dollar - $5000)
availableVABAmount = 50 * 1e6 * (10 ** IERC20Metadata(vabToken).decimals()); // 50M
// disputLimitAmount = 75 * 1e6 * (10**IERC20Metadata(vabToken).decimals()); // 75M
subscriptionAmount = 299 * (10 ** IERC20Metadata(usdcToken).decimals()) / 100; // amount in cash(usd dollar - $2.99)
minVoteCount = 1; //5;
minPropertyList = [
7 days, // 0:
7 days, // 1:
7 days, // 2:
7 days, // 3:
7 days, // 4:
2 * 1e5, // 5: 0.002%
1 days, // 6:
7 days, // 7:
20 * (10 ** IERC20Metadata(usdcToken).decimals()), //8: amount in cash(usd dollar - $20)
2 * 1e8, // 9: percent(2%)
5 * (10 ** IERC20Metadata(usdcToken).decimals()), // 10: amount in cash(usd dollar - $5)
5 * (10 ** IERC20Metadata(usdcToken).decimals()), // 11: amount in cash(usd dollar - $5)
1 * 1e8, // 12: 1%
1, // 13:
3 * 1e8, // 14: 3%
50 * 1e6 * (10 ** IERC20Metadata(vabToken).decimals()), // 15: 50M
7 days, // 16:
5 * 1e8, // 17: 5% (1% = 1e8)
7 days, // 18:
299 * (10 ** IERC20Metadata(usdcToken).decimals()) / 100, // 19: amount in cash(usd dollar - $2.99)
1 * 1e8 // 20: 1%
];
maxPropertyList = [
90 days, // 0:
90 days, // 1:
90 days, // 2:
90 days, // 3:
90 days, // 4:
58 * 1e5, // 5: 0.058%
90 days, // 6:
90 days, // 7:
500 * (10 ** IERC20Metadata(usdcToken).decimals()), //8: amount in cash(usd dollar - $500)
10 * 1e8, // 9: percent(10%)
10 * 1e6 * (10 ** IERC20Metadata(usdcToken).decimals()), // 10: amount in cash(usd dollar - $10,000,000)
10 * 1e6 * (10 ** IERC20Metadata(usdcToken).decimals()), // 11: amount in cash(usd dollar - $10,000,000)
10 * 1e8, // 12: 10%
10, // 13:
10 * 1e8, // 14: 10%
200 * 1e6 * (10 ** IERC20Metadata(vabToken).decimals()), // 15: 200M
90 days, // 16:
30 * 1e8, // 17: 30% (1% = 1e8)
90 days, // 18:
9999 * (10 ** IERC20Metadata(usdcToken).decimals()) / 100, // 19: amount in cash(usd dollar - $99.99)
20 * 1e8 // 20: 20%
];
}
function updateForTesting() external onlyDeployer nonReentrant {
require(Helper.isTestNet(), "apply on testnet");
filmVotePeriod = 10 minutes; // 10 days;
boardVotePeriod = 10 minutes; // 14 days;
agentVotePeriod = 10 minutes; // 10 days;
disputeGracePeriod = 10 minutes; // 30 days
propertyVotePeriod = 10 minutes; // 10 days;
rewardVotePeriod = 10 minutes; // 30 days;
lockPeriod = 10 minutes; //30 days;
filmRewardClaimPeriod = 10 minutes; // 30 days;
address vabToken = IOwnablee(OWNABLE).PAYOUT_TOKEN();
availableVABAmount = (10 ** IERC20Metadata(vabToken).decimals()); // 1
}
/// =================== proposals for replacing auditor ==============
/// @notice Anyone($100 fee in VAB) create a proposal for replacing Auditor
function proposalAuditor(address _agent, string memory _title, string memory _description)
external
onlyMajor
nonReentrant
{
require(_agent != address(0), "pA: zero");
require(IOwnablee(OWNABLE).auditor() != _agent, "pA: already auditor");
require(isGovWhitelist[1][_agent] == 0, "pA: already candidate");
__paidFee(proposalFeeAmount);
GovProposal storage ap = govProposalInfo[1][agentList.length];
ap.title = _title;
ap.description = _description;
ap.createTime = block.timestamp;
ap.value = _agent;
ap.creator = msg.sender;
ap.status = Helper.Status.LISTED;
// add proposal data to array for calculating rewards
ap.proposalID = IStakingPool(STAKING_POOL).addProposalData(msg.sender, block.timestamp, agentVotePeriod);
governanceProposalCount += 1;
userGovProposalCount[msg.sender] += 1;
isGovWhitelist[1][_agent] = 1;
allGovProposalInfo[1].push(_agent);
agentList.push(Agent(_agent, IStakingPool(STAKING_POOL).getStakeAmount(msg.sender)));
emit AuditorProposalCreated(msg.sender, _agent, _title, _description);
}
/// @notice Check if proposal fee transferred from studio to stakingPool
// Get expected VAB amount from UniswapV2 and then Transfer VAB: user(studio) -> stakingPool.
function __paidFee(uint256 _payAmount) private {
address usdcToken = IOwnablee(OWNABLE).USDC_TOKEN();
address vabToken = IOwnablee(OWNABLE).PAYOUT_TOKEN();
uint256 expectVABAmount = IUniHelper(UNI_HELPER).expectedAmount(_payAmount, usdcToken, vabToken);
require(expectVABAmount != 0, "pFee: Not paid fee");
Helper.safeTransferFrom(vabToken, msg.sender, address(this), expectVABAmount);
if (IERC20(vabToken).allowance(address(this), STAKING_POOL) == 0) {
Helper.safeApprove(vabToken, STAKING_POOL, IERC20(vabToken).totalSupply());
}
IStakingPool(STAKING_POOL).addRewardToPool(expectVABAmount);
}
// =================== DAO fund rewards proposal ====================
function proposalRewardFund(address _rewardAddress, string memory _title, string memory _description)
external
onlyMajor
nonReentrant
{
require(_rewardAddress != address(0), "pRF: zero");
require(isGovWhitelist[3][_rewardAddress] == 0, "pRF: already candidate");
__paidFee(10 * proposalFeeAmount);
GovProposal storage rp = govProposalInfo[3][rewardAddressList.length];
rp.title = _title;
rp.description = _description;
rp.createTime = block.timestamp;
rp.value = _rewardAddress;
rp.creator = msg.sender;
rp.status = Helper.Status.LISTED;
// add proposal data to array for calculating rewards
rp.proposalID = IStakingPool(STAKING_POOL).addProposalData(msg.sender, block.timestamp, rewardVotePeriod);
isGovWhitelist[3][_rewardAddress] = 1;
governanceProposalCount += 1;
userGovProposalCount[msg.sender] += 1;
allGovProposalInfo[3].push(_rewardAddress);
rewardAddressList.push(_rewardAddress);
emit RewardFundProposalCreated(msg.sender, _rewardAddress, _title, _description);
}
// =================== FilmBoard proposal ====================
/// @notice Anyone($100 fee of VAB) create a proposal with the case to be added to film board
function proposalFilmBoard(address _member, string memory _title, string memory _description)
external
onlyStaker
nonReentrant
{
require(_member != address(0), "pFB: zero");
require(isGovWhitelist[2][_member] == 0, "pFB: already candidate");
__paidFee(proposalFeeAmount);
GovProposal storage bp = govProposalInfo[2][filmBoardCandidates.length];
bp.title = _title;
bp.description = _description;
bp.createTime = block.timestamp;
bp.value = _member;
bp.creator = msg.sender;
bp.status = Helper.Status.LISTED;
// add proposal data to array for calculating rewards
bp.proposalID = IStakingPool(STAKING_POOL).addProposalData(msg.sender, block.timestamp, boardVotePeriod);
isGovWhitelist[2][_member] = 1;
governanceProposalCount += 1;
userGovProposalCount[msg.sender] += 1;
allGovProposalInfo[2].push(_member);
filmBoardCandidates.push(_member);
emit FilmBoardProposalCreated(msg.sender, _member, _title, _description);
}
/// @notice Remove a member from whitelist if he didn't vote to any propsoal for over 3 months
function removeFilmBoardMember(address _member) external onlyStaker nonReentrant {
require(isGovWhitelist[2][_member] == 2, "rFBM: not board member");
require(maxAllowPeriod < block.timestamp - IVote(VOTE).getLastVoteTime(_member), "rFBM: e1");
require(maxAllowPeriod > block.timestamp - IStakingPool(STAKING_POOL).lastfundProposalCreateTime(), "rFBM: e2");
__removeBoardMember(_member);
isGovWhitelist[2][_member] = 0;
emit FilmBoardMemberRemoved(msg.sender, _member);
}
function __removeBoardMember(address _member) private {
for (uint256 k = 0; k < filmBoardMembers.length; k++) {
if (_member == filmBoardMembers[k]) {
filmBoardMembers[k] = filmBoardMembers[filmBoardMembers.length - 1];
filmBoardMembers.pop();
break;
}
}
}
/// @notice Get gov address list
// (1=>agentList, 2=>boardCandidateList, 3=>rewardAddressList, 4=>rest=>boardMemberList)
function getGovProposalList(uint256 _flag) external view returns (address[] memory) {
require(_flag != 0 && _flag < 5, "bad flag");
if (_flag == 1) {
address[] memory list = new address[](agentList.length);
for (uint256 k = 0; k < agentList.length; k++) {
list[k] = agentList[k].agent;
}
return list;
} else if (_flag == 2) {
return filmBoardCandidates;
} else if (_flag == 3) {
return rewardAddressList;
} else {
return filmBoardMembers;
}
}
/// @notice Get agent list
function getAgentProposerStakeAmount(uint256 _index) external view returns (uint256) {
return agentList[_index].stakeAmount;
}
/// @notice Get govProposalInfo(agent=>1, board=>2, pool=>3)
function getGovProposalInfo(uint256 _index, uint256 _flag)
external
view
returns (uint256, uint256, uint256, address, address, Helper.Status)
{
GovProposal memory rp = govProposalInfo[_flag][_index];
uint256 cTime_ = rp.createTime;
uint256 aTime_ = rp.approveTime;
uint256 pID_ = rp.proposalID;
address value_ = rp.value;
address creator_ = rp.creator;
Helper.Status status_ = rp.status;
return (cTime_, aTime_, pID_, value_, creator_, status_);
}
function getGovProposalStr(uint256 _index, uint256 _flag) external view returns (string memory, string memory) {
GovProposal memory rp = govProposalInfo[_flag][_index];
string memory title_ = rp.title;
string memory desc_ = rp.description;
return (title_, desc_);
}
// ===================properties proposal ====================
/// @notice proposals for properties
function proposalProperty(uint256 _property, uint256 _flag, string memory _title, string memory _description)
external
onlyStaker
nonReentrant
{
require(_property != 0 && _flag >= 0 && _flag < maxPropertyList.length, "pP: bad value");
require(isPropertyWhitelist[_flag][_property] == 0, "pP: already candidate");
require(minPropertyList[_flag] <= _property && _property <= maxPropertyList[_flag], "pP: invalid");
__paidFee(proposalFeeAmount);
uint256 len;
if (_flag == 0) {
require(filmVotePeriod != _property, "pP: already filmVotePeriod");
len = filmVotePeriodList.length;
filmVotePeriodList.push(_property);
} else if (_flag == 1) {
require(agentVotePeriod != _property, "pP: already agentVotePeriod");
len = agentVotePeriodList.length;
agentVotePeriodList.push(_property);
} else if (_flag == 2) {
require(disputeGracePeriod != _property, "pP: already disputeGracePeriod");
len = disputeGracePeriodList.length;
disputeGracePeriodList.push(_property);
} else if (_flag == 3) {
require(propertyVotePeriod != _property, "pP: already propertyVotePeriod");
len = propertyVotePeriodList.length;
propertyVotePeriodList.push(_property);
} else if (_flag == 4) {
require(lockPeriod != _property, "pP: already lockPeriod");
len = lockPeriodList.length;
lockPeriodList.push(_property);
} else if (_flag == 5) {
require(rewardRate != _property, "pP: already rewardRate");
len = rewardRateList.length;
rewardRateList.push(_property);
} else if (_flag == 6) {
require(filmRewardClaimPeriod != _property, "pP: already filmRewardClaimPeriod");
len = filmRewardClaimPeriodList.length;
filmRewardClaimPeriodList.push(_property);
} else if (_flag == 7) {
require(maxAllowPeriod != _property, "pP: already maxAllowPeriod");
len = maxAllowPeriodList.length;
maxAllowPeriodList.push(_property);
} else if (_flag == 8) {
require(proposalFeeAmount != _property, "pP: already proposalFeeAmount");
len = proposalFeeAmountList.length;
proposalFeeAmountList.push(_property);
} else if (_flag == 9) {
require(fundFeePercent != _property, "pP: already fundFeePercent");
len = fundFeePercentList.length;
fundFeePercentList.push(_property);
} else if (_flag == 10) {
require(minDepositAmount != _property, "pP: already minDepositAmount");
len = minDepositAmountList.length;
minDepositAmountList.push(_property);
} else if (_flag == 11) {
require(maxDepositAmount != _property, "pP: already maxDepositAmount");
len = maxDepositAmountList.length;
maxDepositAmountList.push(_property);
} else if (_flag == 12) {
require(maxMintFeePercent != _property, "pP: already maxMintFeePercent");
len = maxMintFeePercentList.length;
maxMintFeePercentList.push(_property);
} else if (_flag == 13) {
require(minVoteCount != _property, "pP: already minVoteCount");
len = minVoteCountList.length;
minVoteCountList.push(_property);
} else if (_flag == 14) {
require(minStakerCountPercent != _property, "pP: already minStakerCountPercent");
len = minStakerCountPercentList.length;
minStakerCountPercentList.push(_property);
} else if (_flag == 15) {
require(availableVABAmount != _property, "pP: already availableVABAmount");
len = availableVABAmountList.length;
availableVABAmountList.push(_property);
} else if (_flag == 16) {
require(boardVotePeriod != _property, "pP: already boardVotePeriod");
len = boardVotePeriodList.length;
boardVotePeriodList.push(_property);
} else if (_flag == 17) {
require(boardVoteWeight != _property, "pP: already boardVoteWeight");
len = boardVoteWeightList.length;
boardVoteWeightList.push(_property);
} else if (_flag == 18) {
require(rewardVotePeriod != _property, "pP: already rewardVotePeriod");
len = rewardVotePeriodList.length;
rewardVotePeriodList.push(_property);
} else if (_flag == 19) {
require(subscriptionAmount != _property, "pP: already subscriptionAmount");
len = subscriptionAmountList.length;
subscriptionAmountList.push(_property);
} else if (_flag == 20) {
require(boardRewardRate != _property, "pP: already boardRewardRate");
len = boardRewardRateList.length;
boardRewardRateList.push(_property);
}
ProProposal storage pp = proProposalInfo[_flag][len];
pp.title = _title;
pp.description = _description;
pp.createTime = block.timestamp;
pp.value = _property;
pp.creator = msg.sender;
pp.status = Helper.Status.LISTED;
// add proposal data to array for calculating rewards
pp.proposalID = IStakingPool(STAKING_POOL).addProposalData(msg.sender, block.timestamp, propertyVotePeriod);
governanceProposalCount += 1;
userGovProposalCount[msg.sender] += 1;
isPropertyWhitelist[_flag][_property] = 1;
emit PropertyProposalCreated(msg.sender, _property, _flag, _title, _description);
}
/// @notice Get property proposal list
function getPropertyProposalList(uint256 _flag) public view returns (uint256[] memory _list) {
if (_flag == 0) _list = filmVotePeriodList;
else if (_flag == 1) _list = agentVotePeriodList;
else if (_flag == 2) _list = disputeGracePeriodList;
else if (_flag == 3) _list = propertyVotePeriodList;
else if (_flag == 4) _list = lockPeriodList;
else if (_flag == 5) _list = rewardRateList;
else if (_flag == 6) _list = filmRewardClaimPeriodList;
else if (_flag == 7) _list = maxAllowPeriodList;
else if (_flag == 8) _list = proposalFeeAmountList;
else if (_flag == 9) _list = fundFeePercentList;
else if (_flag == 10) _list = minDepositAmountList;
else if (_flag == 11) _list = maxDepositAmountList;
else if (_flag == 12) _list = maxMintFeePercentList;
else if (_flag == 13) _list = minVoteCountList;
else if (_flag == 14) _list = minStakerCountPercentList;
else if (_flag == 15) _list = availableVABAmountList;
else if (_flag == 16) _list = boardVotePeriodList;
else if (_flag == 17) _list = boardVoteWeightList;
else if (_flag == 18) _list = rewardVotePeriodList;
else if (_flag == 19) _list = subscriptionAmountList;
else if (_flag == 20) _list = boardRewardRateList;
}
/// @notice Get property proposal created time
function getPropertyProposalInfo(uint256 _index, uint256 _flag)
external
view
returns (uint256, uint256, uint256, uint256, address, Helper.Status)
{
ProProposal memory rp = proProposalInfo[_flag][_index];
uint256 cTime_ = rp.createTime;
uint256 aTime_ = rp.approveTime;
uint256 pID_ = rp.proposalID;
uint256 value_ = rp.value;
address creator_ = rp.creator;
Helper.Status status_ = rp.status;
return (cTime_, aTime_, pID_, value_, creator_, status_);
}
function getPropertyProposalStr(uint256 _index, uint256 _flag)
external
view
returns (string memory, string memory)
{
ProProposal memory rp = proProposalInfo[_flag][_index];
string memory title_ = rp.title;
string memory desc_ = rp.description;
return (title_, desc_);
}
function updatePropertyProposal(uint256 _index, uint256 _flag, uint256 _approveStatus) external onlyVote {
uint256 property = proProposalInfo[_flag][_index].value;
// update approve time
proProposalInfo[_flag][_index].approveTime = block.timestamp;
// update approve status
if (_approveStatus == 1) {
proProposalInfo[_flag][_index].status = Helper.Status.UPDATED;
isPropertyWhitelist[_flag][property] = 2;
} else {
proProposalInfo[_flag][_index].status = Helper.Status.REJECTED;
isPropertyWhitelist[_flag][property] = 0;
}
// update main item
if (_approveStatus == 1) {
if (_flag == 0) {
filmVotePeriod = property;
} else if (_flag == 1) {
agentVotePeriod = property;
} else if (_flag == 2) {
disputeGracePeriod = property;
} else if (_flag == 3) {
propertyVotePeriod = property;
} else if (_flag == 4) {
lockPeriod = property;
} else if (_flag == 5) {
rewardRate = property;
} else if (_flag == 6) {
filmRewardClaimPeriod = property;
} else if (_flag == 7) {
maxAllowPeriod = property;
} else if (_flag == 8) {
proposalFeeAmount = property;
} else if (_flag == 9) {
fundFeePercent = property;
} else if (_flag == 10) {
minDepositAmount = property;
} else if (_flag == 11) {
maxDepositAmount = property;
} else if (_flag == 12) {
maxMintFeePercent = property;
} else if (_flag == 13) {
minVoteCount = property;
} else if (_flag == 14) {
minStakerCountPercent = property;
} else if (_flag == 15) {
availableVABAmount = property;
} else if (_flag == 16) {
boardVotePeriod = property;
} else if (_flag == 17) {
boardVoteWeight = property;
} else if (_flag == 18) {
rewardVotePeriod = property;
} else if (_flag == 19) {
subscriptionAmount = property;
} else if (_flag == 20) {
boardRewardRate = property;
}
}
}
function updateGovProposal(
uint256 _index,
uint256 _flag, // 1=>agent, 2=>board, 3=>pool
uint256 _approveStatus // 1/0
) external onlyVote {
address member = govProposalInfo[_flag][_index].value;
// update approve time
govProposalInfo[_flag][_index].approveTime = block.timestamp;
// update approve status
if (_approveStatus == 5) {
// replaced
govProposalInfo[_flag][_index].status = Helper.Status.REPLACED;
isGovWhitelist[_flag][member] = 2;
} else if (_approveStatus == 1) {
govProposalInfo[_flag][_index].status = Helper.Status.UPDATED;
isGovWhitelist[_flag][member] = 2;
} else {
govProposalInfo[_flag][_index].status = Helper.Status.REJECTED;
isGovWhitelist[_flag][member] = 0;
}
// update main item
if (_flag == 3 && _approveStatus == 1) {
DAO_FUND_REWARD = member;
IStakingPool(STAKING_POOL).calcMigrationVAB();
}
if (_flag == 2 && _approveStatus == 1) {
filmBoardMembers.push(member);
}
}
function checkGovWhitelist(uint256 _flag, address _address) external view returns (uint256) {
return isGovWhitelist[_flag][_address];
}
function checkPropertyWhitelist(uint256 _flag, uint256 _property) external view returns (uint256) {
return isPropertyWhitelist[_flag][_property];
}
function getAllGovProposalInfo(uint256 _flag) external view returns (address[] memory) {
return allGovProposalInfo[_flag];
}
///================ @dev Update the property value for only testing in the testnet
// we won't deploy this function in the mainnet
function updatePropertyForTesting(uint256 _value, uint256 _flag) external onlyDeployer {
require(Helper.isTestNet(), "apply on testnet");
require(_value != 0, "test: Zero value");
if (_flag == 0) filmVotePeriod = _value;
else if (_flag == 1) agentVotePeriod = _value;
else if (_flag == 2) disputeGracePeriod = _value;
else if (_flag == 3) propertyVotePeriod = _value;
else if (_flag == 4) lockPeriod = _value;
else if (_flag == 5) rewardRate = _value;
else if (_flag == 6) filmRewardClaimPeriod = _value;
else if (_flag == 7) maxAllowPeriod = _value;
else if (_flag == 8) proposalFeeAmount = _value;
else if (_flag == 9) fundFeePercent = _value;
else if (_flag == 10) minDepositAmount = _value;
else if (_flag == 11) maxDepositAmount = _value;
else if (_flag == 12) maxMintFeePercent = _value;
else if (_flag == 13) availableVABAmount = _value;
else if (_flag == 14) boardVotePeriod = _value;
else if (_flag == 15) boardVoteWeight = _value;
else if (_flag == 16) rewardVotePeriod = _value;
else if (_flag == 17) subscriptionAmount = _value;
else if (_flag == 18) minVoteCount = _value;
else if (_flag == 19) minStakerCountPercent = _value;
// else if(_flag == 20) disputLimitAmount = _value;
}
/// @dev Update the rewardAddress for only testing in the testnet
function updateDAOFundForTesting(address _address) external onlyDeployer {
require(Helper.isTestNet(), "apply on testnet");
DAO_FUND_REWARD = _address;
}
function updateAvailableVABForTesting(uint256 _amount) external onlyDeployer {
require(Helper.isTestNet(), "apply on testnet");
availableVABAmount = _amount;
// disputLimitAmount = _amount * 3;
}
function addAddressToFilmBoardForTesting(address _address) external onlyDeployer {
require(Helper.isTestNet(), "apply on testnet");
filmBoardMembers.push(_address);
isGovWhitelist[2][_address] = 2;
}
}