@@ -188,7 +188,7 @@ contract Havven is ExternStateToken {
188
188
189
189
/* A quantity of nomins greater than this ratio
190
190
* may not be issued against a given value of havvens. */
191
- uint public issuanceRatio = 5 * UNIT / 100 ;
191
+ uint public issuanceRatio = UNIT / 5 ;
192
192
/* No more nomins may be issued than the value of havvens backing them. */
193
193
uint constant MAX_ISSUANCE_RATIO = UNIT;
194
194
@@ -210,16 +210,51 @@ contract Havven is ExternStateToken {
210
210
* If the provided address is 0x0, then a fresh one will be constructed with the contract owning all tokens.
211
211
* @param _owner The owner of this contract.
212
212
*/
213
- constructor (address _proxy , TokenState _tokenState , address _owner , address _oracle , uint _price )
214
- ExternStateToken (_proxy, TOKEN_NAME, TOKEN_SYMBOL, HAVVEN_SUPPLY, _tokenState, _owner )
215
- /* Owned is initialised in ExternStateToken */
213
+ constructor (address _proxy , TokenState _tokenState , address _owner , address _oracle ,
214
+ uint _price , address [] _issuers , Havven _oldHavven )
215
+ ExternStateToken (_proxy, _tokenState, TOKEN_NAME, TOKEN_SYMBOL, HAVVEN_SUPPLY, _owner)
216
216
public
217
217
{
218
218
oracle = _oracle;
219
- feePeriodStartTime = now ;
220
- lastFeePeriodStartTime = now - feePeriodDuration;
221
219
price = _price;
222
220
lastPriceUpdateTime = now ;
221
+
222
+ uint i;
223
+ if (_oldHavven == address (0 )) {
224
+ feePeriodStartTime = now ;
225
+ lastFeePeriodStartTime = now - feePeriodDuration;
226
+ for (i = 0 ; i < _issuers.length ; i++ ) {
227
+ isIssuer[_issuers[i]] = true ;
228
+ }
229
+ } else {
230
+ feePeriodStartTime = _oldHavven.feePeriodStartTime ();
231
+ lastFeePeriodStartTime = _oldHavven.lastFeePeriodStartTime ();
232
+
233
+ uint cbs;
234
+ uint lab;
235
+ uint lm;
236
+ (cbs, lab, lm) = _oldHavven.totalIssuanceData ();
237
+ totalIssuanceData.currentBalanceSum = cbs;
238
+ totalIssuanceData.lastAverageBalance = lab;
239
+ totalIssuanceData.lastModified = lm;
240
+
241
+ for (i = 0 ; i < _issuers.length ; i++ ) {
242
+ address issuer = _issuers[i];
243
+ isIssuer[issuer] = true ;
244
+ uint nomins = _oldHavven.nominsIssued (issuer);
245
+ if (nomins == 0 ) {
246
+ // It is not valid in general to skip those with no currently-issued nomins.
247
+ // But for this release, issuers with nonzero issuanceData have current issuance.
248
+ continue ;
249
+ }
250
+ (cbs, lab, lm) = _oldHavven.issuanceData (issuer);
251
+ nominsIssued[issuer] = nomins;
252
+ issuanceData[issuer].currentBalanceSum = cbs;
253
+ issuanceData[issuer].lastAverageBalance = lab;
254
+ issuanceData[issuer].lastModified = lm;
255
+ }
256
+ }
257
+
223
258
}
224
259
225
260
/* ========== SETTERS ========== */
@@ -372,11 +407,7 @@ contract Havven is ExternStateToken {
372
407
returns (bool )
373
408
{
374
409
address sender = messageSender;
375
- /* If they have enough available Havvens, it could be that
376
- * their havvens are escrowed, however the transfer would then
377
- * fail. This means that escrowed havvens are locked first,
378
- * and then the actual transferable ones. */
379
- require (nominsIssued[sender] == 0 || value <= availableHavvens (sender));
410
+ require (nominsIssued[sender] == 0 || value <= transferableHavvens (sender));
380
411
/* Perform the transfer: if there is a problem,
381
412
* an exception will be thrown in this call. */
382
413
_transfer_byProxy (sender, to, value);
@@ -393,7 +424,7 @@ contract Havven is ExternStateToken {
393
424
returns (bool )
394
425
{
395
426
address sender = messageSender;
396
- require (nominsIssued[sender ] == 0 || value <= availableHavvens (from));
427
+ require (nominsIssued[from ] == 0 || value <= transferableHavvens (from));
397
428
/* Perform the transfer: if there is a problem,
398
429
* an exception will be thrown in this call. */
399
430
_transferFrom_byProxy (sender, from, to, value);
@@ -406,7 +437,7 @@ contract Havven is ExternStateToken {
406
437
* and then deposit it into their nomin account.
407
438
*/
408
439
function withdrawFees ()
409
- public
440
+ external
410
441
optionalProxy
411
442
{
412
443
address sender = messageSender;
@@ -451,20 +482,20 @@ contract Havven is ExternStateToken {
451
482
internal
452
483
{
453
484
/* update the total balances first */
454
- totalIssuanceData = updatedIssuanceData (lastTotalSupply, totalIssuanceData);
485
+ totalIssuanceData = computeIssuanceData (lastTotalSupply, totalIssuanceData);
455
486
456
487
if (issuanceData[account].lastModified < feePeriodStartTime) {
457
488
hasWithdrawnFees[account] = false ;
458
489
}
459
490
460
- issuanceData[account] = updatedIssuanceData (preBalance, issuanceData[account]);
491
+ issuanceData[account] = computeIssuanceData (preBalance, issuanceData[account]);
461
492
}
462
493
463
494
464
495
/**
465
496
* @notice Compute the new IssuanceData on the old balance
466
497
*/
467
- function updatedIssuanceData (uint preBalance , IssuanceData preIssuance )
498
+ function computeIssuanceData (uint preBalance , IssuanceData preIssuance )
468
499
internal
469
500
view
470
501
returns (IssuanceData)
@@ -609,41 +640,100 @@ contract Havven is ExternStateToken {
609
640
if (issued > max) {
610
641
return 0 ;
611
642
} else {
612
- return max - issued;
643
+ return safeSub (max, issued);
644
+ }
645
+ }
646
+
647
+ /**
648
+ * @notice The total havvens owned by this account, both escrowed and unescrowed,
649
+ * against which nomins can be issued.
650
+ * This includes those already being used as collateral (locked), and those
651
+ * available for further issuance (unlocked).
652
+ */
653
+ function collateral (address account )
654
+ public
655
+ view
656
+ returns (uint )
657
+ {
658
+ uint bal = tokenState.balanceOf (account);
659
+ if (escrow != address (0 )) {
660
+ bal = safeAdd (bal, escrow.balanceOf (account));
613
661
}
662
+ return bal;
614
663
}
615
664
616
665
/**
617
- * @notice Havvens that are locked, which can exceed the user 's total balance + escrowed
666
+ * @notice The collateral that would be locked by issuance , which can exceed the account 's actual collateral.
618
667
*/
619
- function lockedHavvens (address account )
668
+ function issuanceDraft (address account )
620
669
public
621
670
view
622
671
returns (uint )
623
672
{
624
- if (nominsIssued[account] == 0 ) {
673
+ uint issued = nominsIssued[account];
674
+ if (issued == 0 ) {
625
675
return 0 ;
626
676
}
627
- return USDtoHAV (safeDiv_dec (nominsIssued[account] , issuanceRatio));
677
+ return USDtoHAV (safeDiv_dec (issued , issuanceRatio));
628
678
}
629
679
630
680
/**
631
- * @notice Havvens that are not locked, available for issuance
681
+ * @notice Collateral that has been locked due to issuance, and cannot be
682
+ * transferred to other addresses. This is capped at the account's total collateral.
632
683
*/
633
- function availableHavvens (address account )
684
+ function lockedCollateral (address account )
634
685
public
635
686
view
636
687
returns (uint )
637
688
{
638
- uint locked = lockedHavvens (account);
639
- uint bal = tokenState. balanceOf (account);
640
- if (escrow != address ( 0 ) ) {
641
- bal += escrow. balanceOf (account) ;
689
+ uint debt = issuanceDraft (account);
690
+ uint collat = collateral (account);
691
+ if (debt > collat ) {
692
+ return collat ;
642
693
}
643
- if (locked > bal) {
694
+ return debt;
695
+ }
696
+
697
+ /**
698
+ * @notice Collateral that is not locked and available for issuance.
699
+ */
700
+ function unlockedCollateral (address account )
701
+ public
702
+ view
703
+ returns (uint )
704
+ {
705
+ uint locked = lockedCollateral (account);
706
+ uint collat = collateral (account);
707
+ return safeSub (collat, locked);
708
+ }
709
+
710
+ /**
711
+ * @notice The number of havvens that are free to be transferred by an account.
712
+ * @dev If they have enough available Havvens, it could be that
713
+ * their havvens are escrowed, however the transfer would then
714
+ * fail. This means that escrowed havvens are locked first,
715
+ * and then the actual transferable ones.
716
+ */
717
+ function transferableHavvens (address account )
718
+ public
719
+ view
720
+ returns (uint )
721
+ {
722
+ uint draft = issuanceDraft (account);
723
+ uint collat = collateral (account);
724
+ // In the case where the issuanceDraft exceeds the collateral, nothing is free
725
+ if (draft > collat) {
644
726
return 0 ;
645
727
}
646
- return bal - locked;
728
+
729
+ uint bal = balanceOf (account);
730
+ // In the case where the draft exceeds the escrow, but not the whole collateral
731
+ // return the fraction of the balance that remains free
732
+ if (draft > safeSub (collat, bal)) {
733
+ return safeSub (collat, draft);
734
+ }
735
+ // In the case where the draft doesn't exceed the escrow, return the entire balance
736
+ return bal;
647
737
}
648
738
649
739
/**
0 commit comments