-
Notifications
You must be signed in to change notification settings - Fork 0
/
FundingVault.sol
974 lines (755 loc) · 35.9 KB
/
FundingVault.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
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
pragma solidity ^0.4.17;
/*
* source https://github.com/blockbitsio/
* @name Application Entity Generic Contract
* @package BlockBitsIO
* @author Micky Socaci <micky@nowlive.ro>
Used for the ABI interface when assets need to call Application Entity.
This is required, otherwise we end up loading the assets themselves when we load the ApplicationEntity contract
and end up in a loop
*/
contract ApplicationEntityABI {
address public ProposalsEntity;
address public FundingEntity;
address public MilestonesEntity;
address public MeetingsEntity;
address public BountyManagerEntity;
address public TokenManagerEntity;
address public ListingContractEntity;
address public FundingManagerEntity;
address public NewsContractEntity;
bool public _initialized = false;
bool public _locked = false;
uint8 public CurrentEntityState;
uint8 public AssetCollectionNum;
address public GatewayInterfaceAddress;
address public deployerAddress;
address testAddressAllowUpgradeFrom;
mapping (bytes32 => uint8) public EntityStates;
mapping (bytes32 => address) public AssetCollection;
mapping (uint8 => bytes32) public AssetCollectionIdToName;
mapping (bytes32 => uint256) public BylawsUint256;
mapping (bytes32 => bytes32) public BylawsBytes32;
function ApplicationEntity() public;
function getEntityState(bytes32 name) public view returns (uint8);
function linkToGateway( address _GatewayInterfaceAddress, bytes32 _sourceCodeUrl ) external;
function setUpgradeState(uint8 state) public ;
function addAssetProposals(address _assetAddresses) external;
function addAssetFunding(address _assetAddresses) external;
function addAssetMilestones(address _assetAddresses) external;
function addAssetMeetings(address _assetAddresses) external;
function addAssetBountyManager(address _assetAddresses) external;
function addAssetTokenManager(address _assetAddresses) external;
function addAssetFundingManager(address _assetAddresses) external;
function addAssetListingContract(address _assetAddresses) external;
function addAssetNewsContract(address _assetAddresses) external;
function getAssetAddressByName(bytes32 _name) public view returns (address);
function setBylawUint256(bytes32 name, uint256 value) public;
function getBylawUint256(bytes32 name) public view returns (uint256);
function setBylawBytes32(bytes32 name, bytes32 value) public;
function getBylawBytes32(bytes32 name) public view returns (bytes32);
function initialize() external returns (bool);
function getParentAddress() external view returns(address);
function createCodeUpgradeProposal( address _newAddress, bytes32 _sourceCodeUrl ) external returns (uint256);
function acceptCodeUpgradeProposal(address _newAddress) external;
function initializeAssetsToThisApplication() external returns (bool);
function transferAssetsToNewApplication(address _newAddress) external returns (bool);
function lock() external returns (bool);
function canInitiateCodeUpgrade(address _sender) public view returns(bool);
function doStateChanges() public;
function hasRequiredStateChanges() public view returns (bool);
function anyAssetHasChanges() public view returns (bool);
function extendedAnyAssetHasChanges() internal view returns (bool);
function getRequiredStateChanges() public view returns (uint8, uint8);
function getTimestamp() view public returns (uint256);
}
/*
* source https://github.com/blockbitsio/
* @name Token Contract
* @package BlockBitsIO
* @author Micky Socaci <micky@nowlive.ro>
Zeppelin ERC20 Standard Token
*/
contract ABIToken {
string public symbol;
string public name;
uint8 public decimals;
uint256 public totalSupply;
string public version;
mapping (address => uint256) public balances;
mapping (address => mapping (address => uint256)) allowed;
address public manager;
address public deployer;
bool public mintingFinished = false;
bool public initialized = false;
function transfer(address _to, uint256 _value) public returns (bool);
function balanceOf(address _owner) public view returns (uint256 balance);
function transferFrom(address _from, address _to, uint256 _value) public returns (bool);
function approve(address _spender, uint256 _value) public returns (bool);
function allowance(address _owner, address _spender) public view returns (uint256 remaining);
function increaseApproval(address _spender, uint _addedValue) public returns (bool success);
function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool success);
function mint(address _to, uint256 _amount) public returns (bool);
function finishMinting() public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 indexed value);
event Approval(address indexed owner, address indexed spender, uint256 indexed value);
event Mint(address indexed to, uint256 amount);
event MintFinished();
}
/*
* source https://github.com/blockbitsio/
* @name Application Asset Contract ABI
* @package BlockBitsIO
* @author Micky Socaci <micky@nowlive.ro>
Any contract inheriting this will be usable as an Asset in the Application Entity
*/
contract ABIApplicationAsset {
bytes32 public assetName;
uint8 public CurrentEntityState;
uint8 public RecordNum;
bool public _initialized;
bool public _settingsApplied;
address public owner;
address public deployerAddress;
mapping (bytes32 => uint8) public EntityStates;
mapping (bytes32 => uint8) public RecordStates;
function setInitialApplicationAddress(address _ownerAddress) public;
function setInitialOwnerAndName(bytes32 _name) external returns (bool);
function getRecordState(bytes32 name) public view returns (uint8);
function getEntityState(bytes32 name) public view returns (uint8);
function applyAndLockSettings() public returns(bool);
function transferToNewOwner(address _newOwner) public returns (bool);
function getApplicationAssetAddressByName(bytes32 _name) public returns(address);
function getApplicationState() public view returns (uint8);
function getApplicationEntityState(bytes32 name) public view returns (uint8);
function getAppBylawUint256(bytes32 name) public view returns (uint256);
function getAppBylawBytes32(bytes32 name) public view returns (bytes32);
function getTimestamp() view public returns (uint256);
}
/*
* source https://github.com/blockbitsio/
* @name Funding Contract ABI
* @package BlockBitsIO
* @author Micky Socaci <micky@nowlive.ro>
Contains the Funding Contract code deployed and linked to the Application Entity
!!! Links directly to Milestones
*/
contract ABIFunding is ABIApplicationAsset {
address public multiSigOutputAddress;
address public DirectInput;
address public MilestoneInput;
address public TokenManagerEntity;
address public FundingManagerEntity;
struct FundingStage {
bytes32 name;
uint8 state;
uint256 time_start;
uint256 time_end;
uint256 amount_cap_soft; // 0 = not enforced
uint256 amount_cap_hard; // 0 = not enforced
uint256 amount_raised; // 0 = not enforced
// funding method settings
uint256 minimum_entry;
uint8 methods; // FundingMethodIds
// token settings
uint256 fixed_tokens;
uint8 price_addition_percentage; //
uint8 token_share_percentage;
uint8 index;
}
mapping (uint8 => FundingStage) public Collection;
uint8 public FundingStageNum;
uint8 public currentFundingStage;
uint256 public AmountRaised;
uint256 public MilestoneAmountRaised;
uint256 public GlobalAmountCapSoft;
uint256 public GlobalAmountCapHard;
uint8 public TokenSellPercentage;
uint256 public Funding_Setting_funding_time_start;
uint256 public Funding_Setting_funding_time_end;
uint256 public Funding_Setting_cashback_time_start;
uint256 public Funding_Setting_cashback_time_end;
uint256 public Funding_Setting_cashback_before_start_wait_duration;
uint256 public Funding_Setting_cashback_duration;
function addFundingStage(
bytes32 _name,
uint256 _time_start,
uint256 _time_end,
uint256 _amount_cap_soft,
uint256 _amount_cap_hard, // required > 0
uint8 _methods,
uint256 _minimum_entry,
uint256 _fixed_tokens,
uint8 _price_addition_percentage,
uint8 _token_share_percentage
)
public;
function addSettings(address _outputAddress, uint256 soft_cap, uint256 hard_cap, uint8 sale_percentage, address _direct, address _milestone ) public;
function getStageAmount(uint8 StageId) public view returns ( uint256 );
function allowedPaymentMethod(uint8 _payment_method) public pure returns (bool);
function receivePayment(address _sender, uint8 _payment_method) payable public returns(bool);
function canAcceptPayment(uint256 _amount) public view returns (bool);
function getValueOverCurrentCap(uint256 _amount) public view returns (uint256);
function isFundingStageUpdateAllowed(uint8 _new_state ) public view returns (bool);
function getRecordStateRequiredChanges() public view returns (uint8);
function doStateChanges() public;
function hasRequiredStateChanges() public view returns (bool);
function getRequiredStateChanges() public view returns (uint8, uint8, uint8);
}
/*
* source https://github.com/blockbitsio/
* @name Milestones Contract
* @package BlockBitsIO
* @author Micky Socaci <micky@nowlive.ro>
Contains the Milestones Contract code deployed and linked to the Application Entity
*/
contract ABIMilestones is ABIApplicationAsset {
struct Record {
bytes32 name;
string description; // will change to hash pointer ( external storage )
uint8 state;
uint256 duration;
uint256 time_start; // start at unixtimestamp
uint256 last_state_change_time; // time of last state change
uint256 time_end; // estimated end time >> can be increased by proposal
uint256 time_ended; // actual end time
uint256 meeting_time;
uint8 funding_percentage;
uint8 index;
}
uint8 public currentRecord;
uint256 public MilestoneCashBackTime = 0;
mapping (uint8 => Record) public Collection;
mapping (bytes32 => bool) public MilestonePostponingHash;
mapping (bytes32 => uint256) public ProposalIdByHash;
function getBylawsProjectDevelopmentStart() public view returns (uint256);
function getBylawsMinTimeInTheFutureForMeetingCreation() public view returns (uint256);
function getBylawsCashBackVoteRejectedDuration() public view returns (uint256);
function addRecord( bytes32 _name, string _description, uint256 _duration, uint8 _perc ) public;
function getMilestoneFundingPercentage(uint8 recordId) public view returns (uint8);
function doStateChanges() public;
function getRecordStateRequiredChanges() public view returns (uint8);
function hasRequiredStateChanges() public view returns (bool);
function afterVoteNoCashBackTime() public view returns ( bool );
function getHash(uint8 actionType, bytes32 arg1, bytes32 arg2) public pure returns ( bytes32 );
function getCurrentHash() public view returns ( bytes32 );
function getCurrentProposalId() internal view returns ( uint256 );
function setCurrentMilestoneMeetingTime(uint256 _meeting_time) public;
function isRecordUpdateAllowed(uint8 _new_state ) public view returns (bool);
function getRequiredStateChanges() public view returns (uint8, uint8, uint8);
function ApplicationIsInDevelopment() public view returns(bool);
function MeetingTimeSetFailure() public view returns (bool);
}
/*
* source https://github.com/blockbitsio/
* @name Proposals Contract
* @package BlockBitsIO
* @author Micky Socaci <micky@nowlive.ro>
Contains the Proposals Contract code deployed and linked to the Application Entity
*/
contract ABIProposals is ABIApplicationAsset {
address public Application;
address public ListingContractEntity;
address public FundingEntity;
address public FundingManagerEntity;
address public TokenManagerEntity;
address public TokenEntity;
address public MilestonesEntity;
struct ProposalRecord {
address creator;
bytes32 name;
uint8 actionType;
uint8 state;
bytes32 hash; // action name + args hash
address addr;
bytes32 sourceCodeUrl;
uint256 extra;
uint256 time_start;
uint256 time_end;
uint256 index;
}
struct VoteStruct {
address voter;
uint256 time;
bool vote;
uint256 power;
bool annulled;
uint256 index;
}
struct ResultRecord {
uint256 totalAvailable;
uint256 requiredForResult;
uint256 totalSoFar;
uint256 yes;
uint256 no;
bool requiresCounting;
}
uint8 public ActiveProposalNum;
uint256 public VoteCountPerProcess;
bool public EmergencyFundingReleaseApproved;
mapping (bytes32 => uint8) public ActionTypes;
mapping (uint8 => uint256) public ActiveProposalIds;
mapping (uint256 => bool) public ExpiredProposalIds;
mapping (uint256 => ProposalRecord) public ProposalsById;
mapping (bytes32 => uint256) public ProposalIdByHash;
mapping (uint256 => mapping (uint256 => VoteStruct) ) public VotesByProposalId;
mapping (uint256 => mapping (address => VoteStruct) ) public VotesByCaster;
mapping (uint256 => uint256) public VotesNumByProposalId;
mapping (uint256 => ResultRecord ) public ResultsByProposalId;
mapping (uint256 => uint256) public lastProcessedVoteIdByProposal;
mapping (uint256 => uint256) public ProcessedVotesByProposal;
mapping (uint256 => uint256) public VoteCountAtProcessingStartByProposal;
function getRecordState(bytes32 name) public view returns (uint8);
function getActionType(bytes32 name) public view returns (uint8);
function getProposalState(uint256 _proposalId) public view returns (uint8);
function getBylawsProposalVotingDuration() public view returns (uint256);
function getBylawsMilestoneMinPostponing() public view returns (uint256);
function getBylawsMilestoneMaxPostponing() public view returns (uint256);
function getHash(uint8 actionType, bytes32 arg1, bytes32 arg2) public pure returns ( bytes32 );
function process() public;
function hasRequiredStateChanges() public view returns (bool);
function getRequiredStateChanges() public view returns (uint8);
function addCodeUpgradeProposal(address _addr, bytes32 _sourceCodeUrl) external returns (uint256);
function createMilestoneAcceptanceProposal() external returns (uint256);
function createMilestonePostponingProposal(uint256 _duration) external returns (uint256);
function getCurrentMilestonePostponingProposalDuration() public view returns (uint256);
function getCurrentMilestoneProposalStatusForType(uint8 _actionType ) public view returns (uint8);
function createEmergencyFundReleaseProposal() external returns (uint256);
function createDelistingProposal(uint256 _projectId) external returns (uint256);
function RegisterVote(uint256 _proposalId, bool _myVote) public;
function hasPreviousVote(uint256 _proposalId, address _voter) public view returns (bool);
function getTotalTokenVotingPower(address _voter) public view returns ( uint256 );
function getVotingPower(uint256 _proposalId, address _voter) public view returns ( uint256 );
function setVoteCountPerProcess(uint256 _perProcess) external;
function ProcessVoteTotals(uint256 _proposalId, uint256 length) public;
function canEndVoting(uint256 _proposalId) public view returns (bool);
function getProposalType(uint256 _proposalId) public view returns (uint8);
function expiryChangesState(uint256 _proposalId) public view returns (bool);
function needsProcessing(uint256 _proposalId) public view returns (bool);
function getMyVoteForCurrentMilestoneRelease(address _voter) public view returns (bool);
function getHasVoteForCurrentMilestoneRelease(address _voter) public view returns (bool);
function getMyVote(uint256 _proposalId, address _voter) public view returns (bool);
}
/*
* source https://github.com/blockbitsio/
* @name Token Manager Contract
* @package BlockBitsIO
* @author Micky Socaci <micky@nowlive.ro>
*/
contract ABITokenManager is ABIApplicationAsset {
address public TokenSCADAEntity;
address public TokenEntity;
address public MarketingMethodAddress;
bool OwnerTokenBalancesReleased = false;
function addSettings(address _scadaAddress, address _tokenAddress, address _marketing ) public;
function getTokenSCADARequiresHardCap() public view returns (bool);
function mint(address _to, uint256 _amount) public returns (bool);
function finishMinting() public returns (bool);
function mintForMarketingPool(address _to, uint256 _amount) external returns (bool);
function ReleaseOwnersLockedTokens(address _multiSigOutputAddress) public returns (bool);
}
/*
* source https://github.com/blockbitsio/
* @name Funding Contract ABI
* @package BlockBitsIO
* @author Micky Socaci <micky@nowlive.ro>
Contains the Funding Contract code deployed and linked to the Application Entity
*/
contract ABIFundingManager is ABIApplicationAsset {
bool public fundingProcessed;
bool FundingPoolBalancesAllocated;
uint8 public VaultCountPerProcess;
uint256 public lastProcessedVaultId;
uint256 public vaultNum;
uint256 public LockedVotingTokens;
bytes32 public currentTask;
mapping (bytes32 => bool) public taskByHash;
mapping (address => address) public vaultList;
mapping (uint256 => address) public vaultById;
function receivePayment(address _sender, uint8 _payment_method, uint8 _funding_stage) payable public returns(bool);
function getMyVaultAddress(address _sender) public view returns (address);
function setVaultCountPerProcess(uint8 _perProcess) external;
function getHash(bytes32 actionType, bytes32 arg1) public pure returns ( bytes32 );
function getCurrentMilestoneProcessed() public view returns (bool);
function processFundingFailedFinished() public view returns (bool);
function processFundingSuccessfulFinished() public view returns (bool);
function getCurrentMilestoneIdHash() internal view returns (bytes32);
function processMilestoneFinished() public view returns (bool);
function processEmergencyFundReleaseFinished() public view returns (bool);
function getAfterTransferLockedTokenBalances(address vaultAddress, bool excludeCurrent) public view returns (uint256);
function VaultRequestedUpdateForLockedVotingTokens(address owner) public;
function doStateChanges() public;
function hasRequiredStateChanges() public view returns (bool);
function getRequiredStateChanges() public view returns (uint8, uint8);
function ApplicationInFundingOrDevelopment() public view returns(bool);
}
/*
* source https://github.com/blockbitsio/
* @name Token Stake Calculation And Distribution Algorithm - Type 3 - Sell a variable amount of tokens for a fixed price
* @package BlockBitsIO
* @author Micky Socaci <micky@nowlive.ro>
Inputs:
Defined number of tokens per wei ( X Tokens = 1 wei )
Received amount of ETH
Generates:
Total Supply of tokens available in Funding Phase respectively Project
Observations:
Will sell the whole supply of Tokens available to Current Funding Phase
Use cases:
Any Funding Phase where you want the first Funding Phase to determine the token supply of the whole Project
*/
contract ABITokenSCADAVariable {
bool public SCADA_requires_hard_cap = true;
bool public initialized;
address public deployerAddress;
function addSettings(address _fundingContract) public;
function requiresHardCap() public view returns (bool);
function getTokensForValueInCurrentStage(uint256 _value) public view returns (uint256);
function getTokensForValueInStage(uint8 _stage, uint256 _value) public view returns (uint256);
function getBoughtTokens( address _vaultAddress, bool _direct ) public view returns (uint256);
}
/*
* source https://github.com/blockbitsio/
* @name Funding Vault
* @package BlockBitsIO
* @author Micky Socaci <micky@nowlive.ro>
each purchase creates a separate funding vault contract
*/
contract FundingVault {
/* Asset initialised or not */
bool public _initialized = false;
/*
Addresses:
vaultOwner - the address of the wallet that stores purchases in this vault ( investor address )
outputAddress - address where funds go upon successful funding or successful milestone release
managerAddress - address of the "FundingManager"
*/
address public vaultOwner ;
address public outputAddress;
address public managerAddress;
/*
Lock and BlackHole settings
*/
bool public allFundingProcessed = false;
bool public DirectFundingProcessed = false;
/*
Assets
*/
// ApplicationEntityABI public ApplicationEntity;
ABIFunding FundingEntity;
ABIFundingManager FundingManagerEntity;
ABIMilestones MilestonesEntity;
ABIProposals ProposalsEntity;
ABITokenSCADAVariable TokenSCADAEntity;
ABIToken TokenEntity ;
/*
Globals
*/
uint256 public amount_direct = 0;
uint256 public amount_milestone = 0;
// bylaws
bool public emergencyFundReleased = false;
uint8 emergencyFundPercentage = 0;
uint256 BylawsCashBackOwnerMiaDuration;
uint256 BylawsCashBackVoteRejectedDuration;
uint256 BylawsProposalVotingDuration;
struct PurchaseStruct {
uint256 unix_time;
uint8 payment_method;
uint256 amount;
uint8 funding_stage;
uint16 index;
}
mapping(uint16 => PurchaseStruct) public purchaseRecords;
uint16 public purchaseRecordsNum;
event EventPaymentReceived(uint8 indexed _payment_method, uint256 indexed _amount, uint16 indexed _index );
event VaultInitialized(address indexed _owner);
function initialize(
address _owner,
address _output,
address _fundingAddress,
address _milestoneAddress,
address _proposalsAddress
)
public
requireNotInitialised
returns(bool)
{
VaultInitialized(_owner);
outputAddress = _output;
vaultOwner = _owner;
// whomever creates this contract is the manager.
managerAddress = msg.sender;
// assets
FundingEntity = ABIFunding(_fundingAddress);
FundingManagerEntity = ABIFundingManager(managerAddress);
MilestonesEntity = ABIMilestones(_milestoneAddress);
ProposalsEntity = ABIProposals(_proposalsAddress);
address TokenManagerAddress = FundingEntity.getApplicationAssetAddressByName("TokenManager");
ABITokenManager TokenManagerEntity = ABITokenManager(TokenManagerAddress);
address TokenAddress = TokenManagerEntity.TokenEntity();
TokenEntity = ABIToken(TokenAddress);
address TokenSCADAAddress = TokenManagerEntity.TokenSCADAEntity();
TokenSCADAEntity = ABITokenSCADAVariable(TokenSCADAAddress);
// set Emergency Fund Percentage if available.
address ApplicationEntityAddress = TokenManagerEntity.owner();
ApplicationEntityABI ApplicationEntity = ApplicationEntityABI(ApplicationEntityAddress);
// get Application Bylaws
emergencyFundPercentage = uint8( ApplicationEntity.getBylawUint256("emergency_fund_percentage") );
BylawsCashBackOwnerMiaDuration = ApplicationEntity.getBylawUint256("cashback_owner_mia_dur") ;
BylawsCashBackVoteRejectedDuration = ApplicationEntity.getBylawUint256("cashback_investor_no") ;
BylawsProposalVotingDuration = ApplicationEntity.getBylawUint256("proposal_voting_duration") ;
// init
_initialized = true;
return true;
}
/*
The funding contract decides if a vault should receive payments or not, since it's the one that creates them,
no point in creating one if you can't accept payments.
*/
mapping (uint8 => uint256) public stageAmounts;
mapping (uint8 => uint256) public stageAmountsDirect;
function addPayment(
uint8 _payment_method,
uint8 _funding_stage
)
public
payable
requireInitialised
onlyManager
returns (bool)
{
if(msg.value > 0 && FundingEntity.allowedPaymentMethod(_payment_method)) {
// store payment
PurchaseStruct storage purchase = purchaseRecords[++purchaseRecordsNum];
purchase.unix_time = now;
purchase.payment_method = _payment_method;
purchase.amount = msg.value;
purchase.funding_stage = _funding_stage;
purchase.index = purchaseRecordsNum;
// assign payment to direct or milestone
if(_payment_method == 1) {
amount_direct+= purchase.amount;
stageAmountsDirect[_funding_stage]+=purchase.amount;
}
if(_payment_method == 2) {
amount_milestone+= purchase.amount;
}
// in order to not iterate through purchase records, we just increase funding stage amount.
// issue with iterating over them, while processing vaults, would be that someone could create a large
// number of payments, which would result in an "out of gas" / stack overflow issue, that would lock
// our contract, so we don't really want to do that.
// doing it this way also saves some gas
stageAmounts[_funding_stage]+=purchase.amount;
EventPaymentReceived( purchase.payment_method, purchase.amount, purchase.index );
return true;
} else {
revert();
}
}
function getBoughtTokens() public view returns (uint256) {
return TokenSCADAEntity.getBoughtTokens( address(this), false );
}
function getDirectBoughtTokens() public view returns (uint256) {
return TokenSCADAEntity.getBoughtTokens( address(this), true );
}
mapping (uint8 => uint256) public etherBalances;
mapping (uint8 => uint256) public tokenBalances;
uint8 public BalanceNum = 0;
bool public BalancesInitialised = false;
function initMilestoneTokenAndEtherBalances() internal
{
if(BalancesInitialised == false) {
uint256 milestoneTokenBalance = TokenEntity.balanceOf(address(this));
uint256 milestoneEtherBalance = this.balance;
// no need to worry about fractions because at the last milestone, we send everything that's left.
// emergency fund takes it's percentage from initial balances.
if(emergencyFundPercentage > 0) {
tokenBalances[0] = milestoneTokenBalance / 100 * emergencyFundPercentage;
etherBalances[0] = milestoneEtherBalance / 100 * emergencyFundPercentage;
milestoneTokenBalance-=tokenBalances[0];
milestoneEtherBalance-=etherBalances[0];
}
// milestones percentages are then taken from what's left.
for(uint8 i = 1; i <= MilestonesEntity.RecordNum(); i++) {
uint8 perc = MilestonesEntity.getMilestoneFundingPercentage(i);
tokenBalances[i] = milestoneTokenBalance / 100 * perc;
etherBalances[i] = milestoneEtherBalance / 100 * perc;
}
BalanceNum = i;
BalancesInitialised = true;
}
}
function ReleaseFundsAndTokens()
public
requireInitialised
onlyManager
returns (bool)
{
// first make sure cashback is not possible, and that we've not processed everything in this vault
if(!canCashBack() && allFundingProcessed == false) {
if(FundingManagerEntity.CurrentEntityState() == FundingManagerEntity.getEntityState("FUNDING_SUCCESSFUL_PROGRESS")) {
// case 1, direct funding only
if(amount_direct > 0 && amount_milestone == 0) {
// if we have direct funding and no milestone balance, transfer everything and lock vault
// to save gas in future processing runs.
// transfer tokens to the investor
TokenEntity.transfer(vaultOwner, TokenEntity.balanceOf( address(this) ) );
// transfer ether to the owner's wallet
outputAddress.transfer(this.balance);
// lock vault.. and enable black hole methods
allFundingProcessed = true;
} else {
// case 2 and 3, direct funding only
if(amount_direct > 0 && DirectFundingProcessed == false ) {
TokenEntity.transfer(vaultOwner, getDirectBoughtTokens() );
// transfer "direct funding" ether to the owner's wallet
outputAddress.transfer(amount_direct);
DirectFundingProcessed = true;
}
// process and initialize milestone balances, emergency fund, etc, once
initMilestoneTokenAndEtherBalances();
}
return true;
} else if(FundingManagerEntity.CurrentEntityState() == FundingManagerEntity.getEntityState("MILESTONE_PROCESS_PROGRESS")) {
// get current milestone so we know which one we need to release funds for.
uint8 milestoneId = MilestonesEntity.currentRecord();
uint256 transferTokens = tokenBalances[milestoneId];
uint256 transferEther = etherBalances[milestoneId];
if(milestoneId == BalanceNum - 1) {
// we're processing the last milestone and balance, this means we're transferring everything left.
// this is done to make sure we've transferred everything, even "ether that got mistakenly sent to this address"
// as well as the emergency fund if it has not been used.
transferTokens = TokenEntity.balanceOf(address(this));
transferEther = this.balance;
}
// set balances to 0 so we can't transfer multiple times.
// tokenBalances[milestoneId] = 0;
// etherBalances[milestoneId] = 0;
// transfer tokens to the investor
TokenEntity.transfer(vaultOwner, transferTokens );
// transfer ether to the owner's wallet
outputAddress.transfer(transferEther);
if(milestoneId == BalanceNum - 1) {
// lock vault.. and enable black hole methods
allFundingProcessed = true;
}
return true;
}
}
return false;
}
function releaseTokensAndEtherForEmergencyFund()
public
requireInitialised
onlyManager
returns (bool)
{
if( emergencyFundReleased == false && emergencyFundPercentage > 0) {
// transfer tokens to the investor
TokenEntity.transfer(vaultOwner, tokenBalances[0] );
// transfer ether to the owner's wallet
outputAddress.transfer(etherBalances[0]);
emergencyFundReleased = true;
return true;
}
return false;
}
function ReleaseFundsToInvestor()
public
requireInitialised
isOwner
{
if(canCashBack()) {
// IF we're doing a cashback
// transfer vault tokens back to owner address
// send all ether to wallet owner
// get token balance
uint256 myBalance = TokenEntity.balanceOf(address(this));
// transfer all vault tokens to owner
if(myBalance > 0) {
TokenEntity.transfer(outputAddress, myBalance );
}
// now transfer all remaining ether back to investor address
vaultOwner.transfer(this.balance);
// update FundingManager Locked Token Amount, so we don't break voting
FundingManagerEntity.VaultRequestedUpdateForLockedVotingTokens( vaultOwner );
// disallow further processing, so we don't break Funding Manager.
// this method can still be called to collect future black hole ether to this vault.
allFundingProcessed = true;
}
}
/*
1 - if the funding of the project Failed, allows investors to claim their locked ether back.
2 - if the Investor votes NO to a Development Milestone Completion Proposal, where the majority
also votes NO allows investors to claim their locked ether back.
3 - project owner misses to set the time for a Development Milestone Completion Meeting allows investors
to claim their locked ether back.
*/
function canCashBack() public view requireInitialised returns (bool) {
// case 1
if(checkFundingStateFailed()) {
return true;
}
// case 2
if(checkMilestoneStateInvestorVotedNoVotingEndedNo()) {
return true;
}
// case 3
if(checkOwnerFailedToSetTimeOnMeeting()) {
return true;
}
return false;
}
function checkFundingStateFailed() public view returns (bool) {
if(FundingEntity.CurrentEntityState() == FundingEntity.getEntityState("FAILED_FINAL") ) {
return true;
}
// also check if funding period ended, and 7 days have passed and no processing was done.
if( FundingEntity.getTimestamp() >= FundingEntity.Funding_Setting_cashback_time_start() ) {
// should only be possible if funding entity has been stuck in processing for more than 7 days.
if( FundingEntity.CurrentEntityState() != FundingEntity.getEntityState("SUCCESSFUL_FINAL") ) {
return true;
}
}
return false;
}
function checkMilestoneStateInvestorVotedNoVotingEndedNo() public view returns (bool) {
if(MilestonesEntity.CurrentEntityState() == MilestonesEntity.getEntityState("VOTING_ENDED_NO") ) {
// first we need to make sure we actually voted.
if( ProposalsEntity.getHasVoteForCurrentMilestoneRelease(vaultOwner) == true) {
// now make sure we voted NO, and if so return true
if( ProposalsEntity.getMyVoteForCurrentMilestoneRelease( vaultOwner ) == false) {
return true;
}
}
}
return false;
}
function checkOwnerFailedToSetTimeOnMeeting() public view returns (bool) {
// Looks like the project owner is missing in action
// they only have to do 1 thing, which is set the meeting time 7 days before the end of the milestone so that
// investors know when they need to show up for a progress report meeting
// as they did not, we consider them missing in action and allow investors to retrieve their locked ether back
if( MilestonesEntity.CurrentEntityState() == MilestonesEntity.getEntityState("DEADLINE_MEETING_TIME_FAILED") ) {
return true;
}
return false;
}
modifier isOwner() {
require(msg.sender == vaultOwner);
_;
}
modifier onlyManager() {
require(msg.sender == managerAddress);
_;
}
modifier requireInitialised() {
require(_initialized == true);
_;
}
modifier requireNotInitialised() {
require(_initialized == false);
_;
}
}