From 0bf83e47eac621f2b8779075d4e0c56efe276be4 Mon Sep 17 00:00:00 2001 From: DominicRomanowski Date: Fri, 22 Jun 2018 13:41:01 +1000 Subject: [PATCH 01/22] small changes to havven to add basic functions and cleanup --- contracts/Havven.sol | 94 +++++++++++++++++++++++++------- tests/contracts/PublicHavven.sol | 4 +- tests/test_Court.py | 2 +- tests/test_FeeCollection.py | 2 +- tests/test_Havven.py | 2 +- tests/test_HavvenEscrow.py | 4 +- tests/test_Issuance.py | 2 +- tests/test_IssuanceController.py | 2 +- tests/test_Nomin.py | 2 +- 9 files changed, 85 insertions(+), 29 deletions(-) diff --git a/contracts/Havven.sol b/contracts/Havven.sol index da2c30bd3c..205118234b 100644 --- a/contracts/Havven.sol +++ b/contracts/Havven.sol @@ -210,7 +210,7 @@ contract Havven is ExternStateToken { * If the provided address is 0x0, then a fresh one will be constructed with the contract owning all tokens. * @param _owner The owner of this contract. */ - constructor(address _proxy, TokenState _tokenState, address _owner, address _oracle, uint _price) + constructor(address _proxy, TokenState _tokenState, address _owner, address _oracle, uint _price, address[] _issuers, uint[] _nominsIssued) ExternStateToken(_proxy, TOKEN_NAME, TOKEN_SYMBOL, HAVVEN_SUPPLY, _tokenState, _owner) /* Owned is initialised in ExternStateToken */ public @@ -220,6 +220,13 @@ contract Havven is ExternStateToken { lastFeePeriodStartTime = now - feePeriodDuration; price = _price; lastPriceUpdateTime = now; + + for (uint i=0; i < _issuers.length; i++) { + address issuer = _issuers[i]; + uint issuedNom = _nominsIssued[i]; + isIssuer[issuer] = true; + } + } /* ========== SETTERS ========== */ @@ -376,7 +383,7 @@ contract Havven is ExternStateToken { * their havvens are escrowed, however the transfer would then * fail. This means that escrowed havvens are locked first, * and then the actual transferable ones. */ - require(nominsIssued[sender] == 0 || value <= availableHavvens(sender)); + require(nominsIssued[sender] == 0 || value <= transferableHavvens(sender)); /* Perform the transfer: if there is a problem, * an exception will be thrown in this call. */ _transfer_byProxy(sender, to, value); @@ -393,7 +400,7 @@ contract Havven is ExternStateToken { returns (bool) { address sender = messageSender; - require(nominsIssued[sender] == 0 || value <= availableHavvens(from)); + require(nominsIssued[sender] == 0 || value <= transferableHavvens(from)); /* Perform the transfer: if there is a problem, * an exception will be thrown in this call. */ _transferFrom_byProxy(sender, from, to, value); @@ -406,7 +413,7 @@ contract Havven is ExternStateToken { * and then deposit it into their nomin account. */ function withdrawFees() - public + external optionalProxy { address sender = messageSender; @@ -451,20 +458,20 @@ contract Havven is ExternStateToken { internal { /* update the total balances first */ - totalIssuanceData = updatedIssuanceData(lastTotalSupply, totalIssuanceData); + totalIssuanceData = computeIssuanceData(lastTotalSupply, totalIssuanceData); if (issuanceData[account].lastModified < feePeriodStartTime) { hasWithdrawnFees[account] = false; } - issuanceData[account] = updatedIssuanceData(preBalance, issuanceData[account]); + issuanceData[account] = computeIssuanceData(preBalance, issuanceData[account]); } /** * @notice Compute the new IssuanceData on the old balance */ - function updatedIssuanceData(uint preBalance, IssuanceData preIssuance) + function computeIssuanceData(uint preBalance, IssuanceData preIssuance) internal view returns (IssuanceData) @@ -609,22 +616,77 @@ contract Havven is ExternStateToken { if (issued > max) { return 0; } else { - return max - issued; + return safeSub(max, issued); + } + } + + /** + * @notice the total havvens that can be used as collateral for issuing nomins by an account. + * This total includes all locked havvens as well. + */ + function collateral(address account) + public + view + returns (uint) + { + uint bal = tokenState.balanceOf(account); + if (escrow != address(0)) { + bal = safeAdd(bal, escrow.balanceOf(account)); } + return bal; } /** - * @notice Havvens that are locked, which can exceed the user's total balance + escrowed + * @notice Locked havvens based on nominsIssued, which can exceed the user's free and escrowed havvens. + */ + function issuanceDraft(address account) + public + view + returns (uint) + { + uint issued = nominsIssued[account]; + if (issued == 0) { + return 0; + } + return USDtoHAV(safeDiv_dec(issued, issuanceRatio)); + } + + /** + * @notice Locked Havvens that are capped at the user's free and escrowed havvens. */ function lockedHavvens(address account) public view returns (uint) { - if (nominsIssued[account] == 0) { + uint debt = issuanceDraft(account); + uint collat = collateral(account); + if (debt > collat) { + return collat; + } + return debt; + } + + /** + * @notice The number of havvens that are free to be transferred by an account. + */ + function transferableHavvens(address account) + public + view + returns (uint) + { + uint draft = issuanceDraft(account); + uint collat = collateral(account); + if (draft > collat) { return 0; } - return USDtoHAV(safeDiv_dec(nominsIssued[account], issuanceRatio)); + + uint bal = balanceOf(account); + if (draft > safeSub(collat, bal)) { + return safeSub(collat, draft); + } + + return bal; } /** @@ -636,14 +698,8 @@ contract Havven is ExternStateToken { returns (uint) { uint locked = lockedHavvens(account); - uint bal = tokenState.balanceOf(account); - if (escrow != address(0)) { - bal += escrow.balanceOf(account); - } - if (locked > bal) { - return 0; - } - return bal - locked; + uint bal = collateral(account); + return safeSub(bal, locked); } /** diff --git a/tests/contracts/PublicHavven.sol b/tests/contracts/PublicHavven.sol index ad433e939b..024f0cff00 100644 --- a/tests/contracts/PublicHavven.sol +++ b/tests/contracts/PublicHavven.sol @@ -15,8 +15,8 @@ contract PublicHavven is Havven { uint constant public MIN_FEE_PERIOD_DURATION = 1 days; uint constant public MAX_FEE_PERIOD_DURATION = 26 weeks; - constructor(address _proxy, TokenState _state, address _owner, address _oracle, uint _price) - Havven(_proxy, _state, _owner, _oracle, _price) + constructor(address _proxy, TokenState _state, address _owner, address _oracle, uint _price, address[] _issuers, uint[] _issuedNomins) + Havven(_proxy, _state, _owner, _oracle, _price, _issuers, _issuedNomins) public {} diff --git a/tests/test_Court.py b/tests/test_Court.py index 260e0244ae..23ad5061c2 100644 --- a/tests/test_Court.py +++ b/tests/test_Court.py @@ -56,7 +56,7 @@ def deployContracts(cls): tokenstate, _ = attempt_deploy(compiled, 'TokenState', MASTER, [MASTER, MASTER]) havven_contract, hvn_txr = attempt_deploy( - compiled, 'PublicHavven', MASTER, [havven_proxy.address, tokenstate.address, MASTER, MASTER, UNIT//2] + compiled, 'PublicHavven', MASTER, [havven_proxy.address, tokenstate.address, MASTER, MASTER, UNIT//2, [], []] ) nomin_contract, nom_txr = attempt_deploy( compiled, 'Nomin', MASTER, [nomin_proxy.address, havven_contract.address, MASTER] diff --git a/tests/test_FeeCollection.py b/tests/test_FeeCollection.py index ec39ae33cb..86a4ae0030 100644 --- a/tests/test_FeeCollection.py +++ b/tests/test_FeeCollection.py @@ -45,7 +45,7 @@ def deployContracts(cls): tokenstate, _ = attempt_deploy(compiled, 'TokenState', MASTER, [MASTER, MASTER]) havven_contract, hvn_txr = attempt_deploy(compiled, 'PublicHavven', - MASTER, [havven_proxy.address, tokenstate.address, MASTER, MASTER, UNIT//2]) + MASTER, [havven_proxy.address, tokenstate.address, MASTER, MASTER, UNIT//2, [], []]) nomin_contract, nom_txr = attempt_deploy(compiled, 'PublicNomin', MASTER, [nomin_proxy.address, havven_contract.address, MASTER]) diff --git a/tests/test_Havven.py b/tests/test_Havven.py index 6b5694ffb2..3c938534dd 100644 --- a/tests/test_Havven.py +++ b/tests/test_Havven.py @@ -52,7 +52,7 @@ def deployContracts(cls): tokenstate, _ = attempt_deploy(compiled, 'TokenState', MASTER, [MASTER, MASTER]) - havven_contract, hvn_txr = attempt_deploy(compiled, 'PublicHavven', MASTER, [havven_proxy.address, tokenstate.address, MASTER, MASTER, UNIT//2]) + havven_contract, hvn_txr = attempt_deploy(compiled, 'PublicHavven', MASTER, [havven_proxy.address, tokenstate.address, MASTER, MASTER, UNIT//2, [], []]) hvn_block = W3.eth.blockNumber nomin_contract, nom_txr = attempt_deploy(compiled, 'Nomin', MASTER, diff --git a/tests/test_HavvenEscrow.py b/tests/test_HavvenEscrow.py index eb104a8c80..918e1f353f 100644 --- a/tests/test_HavvenEscrow.py +++ b/tests/test_HavvenEscrow.py @@ -54,7 +54,7 @@ def deployContracts(cls): tokenstate, _ = attempt_deploy(cls.compiled, 'TokenState', MASTER, [MASTER, MASTER]) - havven_contract, hvn_txr = attempt_deploy(cls.compiled, 'PublicHavven', MASTER, [havven_proxy.address, tokenstate.address, MASTER, MASTER, UNIT//2]) + havven_contract, hvn_txr = attempt_deploy(cls.compiled, 'PublicHavven', MASTER, [havven_proxy.address, tokenstate.address, MASTER, MASTER, UNIT//2, [], []]) hvn_block = W3.eth.blockNumber nomin_contract, nom_txr = attempt_deploy(cls.compiled, 'PublicNomin', @@ -657,7 +657,7 @@ def test_swap_havven(self): # Deploy the new havven contract, with proxy and all. havven_proxy, _ = attempt_deploy(self.compiled, 'Proxy', MASTER, [MASTER]) - havven_contract, _ = attempt_deploy(self.compiled, 'PublicHavven', MASTER, [havven_proxy.address, self.havven_token_state.address, MASTER, MASTER, UNIT//2]) + havven_contract, _ = attempt_deploy(self.compiled, 'PublicHavven', MASTER, [havven_proxy.address, self.havven_token_state.address, MASTER, MASTER, UNIT//2, [], []]) proxied_havven = W3.eth.contract(address=havven_proxy.address, abi=self.compiled['PublicHavven']['abi']) new_havven = PublicHavvenInterface(proxied_havven, "Havven") diff --git a/tests/test_Issuance.py b/tests/test_Issuance.py index 7ef6bf6ad0..6e8d7a2601 100644 --- a/tests/test_Issuance.py +++ b/tests/test_Issuance.py @@ -49,7 +49,7 @@ def deployContracts(cls): tokenstate, _ = attempt_deploy(compiled, 'TokenState', MASTER, [MASTER, MASTER]) havven_contract, hvn_txr = attempt_deploy(compiled, 'PublicHavven', MASTER, - [havven_proxy.address, tokenstate.address, MASTER, MASTER, UNIT//2]) + [havven_proxy.address, tokenstate.address, MASTER, MASTER, UNIT//2, [], []]) nomin_contract, nom_txr = attempt_deploy(compiled, 'PublicNomin', MASTER, diff --git a/tests/test_IssuanceController.py b/tests/test_IssuanceController.py index 9c28fe1c16..210f1333ec 100644 --- a/tests/test_IssuanceController.py +++ b/tests/test_IssuanceController.py @@ -50,7 +50,7 @@ def deployContracts(cls): tokenstate, _ = attempt_deploy(compiled, 'TokenState', MASTER, [MASTER, MASTER]) havven_contract, hvn_txr = attempt_deploy( - compiled, 'PublicHavven', MASTER, [havven_proxy.address, tokenstate.address, MASTER, MASTER, UNIT//2] + compiled, 'PublicHavven', MASTER, [havven_proxy.address, tokenstate.address, MASTER, MASTER, UNIT//2, [], []] ) nomin_contract, nom_txr = attempt_deploy( compiled, 'PublicNomin', MASTER, [nomin_proxy.address, havven_contract.address, MASTER] diff --git a/tests/test_Nomin.py b/tests/test_Nomin.py index bff2fa7e43..652aec3911 100644 --- a/tests/test_Nomin.py +++ b/tests/test_Nomin.py @@ -46,7 +46,7 @@ def deployContracts(cls): ) havven_contract, _ = attempt_deploy( - compiled, "Havven", MASTER, [havven_proxy.address, ZERO_ADDRESS, MASTER, MASTER, UNIT//2] + compiled, "Havven", MASTER, [havven_proxy.address, ZERO_ADDRESS, MASTER, MASTER, UNIT//2, [], []] ) fake_court, _ = attempt_deploy(compiled, 'FakeCourt', MASTER, []) From d983fae17773b715e3444c6aa0fca4c29a6e185a Mon Sep 17 00:00:00 2001 From: DominicRomanowski Date: Fri, 22 Jun 2018 13:55:56 +1000 Subject: [PATCH 02/22] fix to constructor --- contracts/Havven.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/Havven.sol b/contracts/Havven.sol index 205118234b..9af2a478da 100644 --- a/contracts/Havven.sol +++ b/contracts/Havven.sol @@ -223,7 +223,7 @@ contract Havven is ExternStateToken { for (uint i=0; i < _issuers.length; i++) { address issuer = _issuers[i]; - uint issuedNom = _nominsIssued[i]; + nominsIssued[issuer] = _nominsIssued[i]; isIssuer[issuer] = true; } From 960988e869d99306780626a2dcbd5f19facad2d5 Mon Sep 17 00:00:00 2001 From: DominicRomanowski Date: Fri, 22 Jun 2018 14:16:37 +1000 Subject: [PATCH 03/22] moved one function, changed naming to be consistent with use of 'collateral' --- contracts/Havven.sol | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/contracts/Havven.sol b/contracts/Havven.sol index 9af2a478da..6adb63537b 100644 --- a/contracts/Havven.sol +++ b/contracts/Havven.sol @@ -654,7 +654,7 @@ contract Havven is ExternStateToken { /** * @notice Locked Havvens that are capped at the user's free and escrowed havvens. */ - function lockedHavvens(address account) + function lockedCollateral(address account) public view returns (uint) @@ -667,6 +667,19 @@ contract Havven is ExternStateToken { return debt; } + /** + * @notice Havvens that are not locked, available for issuance + */ + function availableCollateral(address account) + public + view + returns (uint) + { + uint locked = lockedHavvens(account); + uint bal = collateral(account); + return safeSub(bal, locked); + } + /** * @notice The number of havvens that are free to be transferred by an account. */ @@ -689,19 +702,6 @@ contract Havven is ExternStateToken { return bal; } - /** - * @notice Havvens that are not locked, available for issuance - */ - function availableHavvens(address account) - public - view - returns (uint) - { - uint locked = lockedHavvens(account); - uint bal = collateral(account); - return safeSub(bal, locked); - } - /** * @notice The value in USD for a given amount of HAV */ From f60991d441df6f22c3cb67731f7384627eb26fa1 Mon Sep 17 00:00:00 2001 From: DominicRomanowski Date: Fri, 22 Jun 2018 15:16:04 +1000 Subject: [PATCH 04/22] changes for review, as well as some minor test edits --- contracts/Havven.sol | 31 +++++++++-------- tests/contract_interfaces/havven_interface.py | 17 ++++++---- tests/contracts/PublicHavven.sol | 2 +- tests/test_Court.py | 6 ++-- tests/test_Havven.py | 34 +++++++++---------- 5 files changed, 49 insertions(+), 41 deletions(-) diff --git a/contracts/Havven.sol b/contracts/Havven.sol index 6adb63537b..e5e33108d5 100644 --- a/contracts/Havven.sol +++ b/contracts/Havven.sol @@ -210,9 +210,9 @@ contract Havven is ExternStateToken { * If the provided address is 0x0, then a fresh one will be constructed with the contract owning all tokens. * @param _owner The owner of this contract. */ - constructor(address _proxy, TokenState _tokenState, address _owner, address _oracle, uint _price, address[] _issuers, uint[] _nominsIssued) + constructor(address _proxy, TokenState _tokenState, address _owner, address _oracle, + uint _price, address[] _issuers, uint[] _nominsIssued) ExternStateToken(_proxy, TOKEN_NAME, TOKEN_SYMBOL, HAVVEN_SUPPLY, _tokenState, _owner) - /* Owned is initialised in ExternStateToken */ public { oracle = _oracle; @@ -379,10 +379,6 @@ contract Havven is ExternStateToken { returns (bool) { address sender = messageSender; - /* If they have enough available Havvens, it could be that - * their havvens are escrowed, however the transfer would then - * fail. This means that escrowed havvens are locked first, - * and then the actual transferable ones. */ require(nominsIssued[sender] == 0 || value <= transferableHavvens(sender)); /* Perform the transfer: if there is a problem, * an exception will be thrown in this call. */ @@ -637,7 +633,7 @@ contract Havven is ExternStateToken { } /** - * @notice Locked havvens based on nominsIssued, which can exceed the user's free and escrowed havvens. + * @notice The collateral that would be locked by issuance, which can exceed the account's actual collateral. */ function issuanceDraft(address account) public @@ -652,9 +648,9 @@ contract Havven is ExternStateToken { } /** - * @notice Locked Havvens that are capped at the user's free and escrowed havvens. + * @notice Collateral that has been locked due to issuance, which is capped at the account's total collateral. */ - function lockedCollateral(address account) + function unavailableCollateral(address account) public view returns (uint) @@ -668,20 +664,24 @@ contract Havven is ExternStateToken { } /** - * @notice Havvens that are not locked, available for issuance + * @notice Collateral that is not locked and available for issuance. */ function availableCollateral(address account) public view returns (uint) { - uint locked = lockedHavvens(account); - uint bal = collateral(account); - return safeSub(bal, locked); + uint locked = unavailableCollateral(account); + uint collat = collateral(account); + return safeSub(collat, locked); } /** * @notice The number of havvens that are free to be transferred by an account. + * @dev If they have enough available Havvens, it could be that + * their havvens are escrowed, however the transfer would then + * fail. This means that escrowed havvens are locked first, + * and then the actual transferable ones. */ function transferableHavvens(address account) public @@ -690,15 +690,18 @@ contract Havven is ExternStateToken { { uint draft = issuanceDraft(account); uint collat = collateral(account); + // In the case where the issuanceDraft exceeds the collateral, nothing is free if (draft > collat) { return 0; } uint bal = balanceOf(account); + // In the case where the draft exceeds the escrow, but not the whole collateral + // return the fraction of the balance that remains free if (draft > safeSub(collat, bal)) { return safeSub(collat, draft); } - + // In the case where the draft doesn't exceed the escrow, return the entire balance return bal; } diff --git a/tests/contract_interfaces/havven_interface.py b/tests/contract_interfaces/havven_interface.py index c836c78b41..81e7323e04 100644 --- a/tests/contract_interfaces/havven_interface.py +++ b/tests/contract_interfaces/havven_interface.py @@ -36,13 +36,18 @@ def __init__(self, contract, name): self.totalIssuanceCurrentBalanceSum = lambda: self.contract.functions.totalIssuanceCurrentBalanceSum().call() self.totalIssuanceLastAverageBalance = lambda: self.contract.functions.totalIssuanceLastAverageBalance().call() self.totalIssuanceLastModified = lambda: self.contract.functions.totalIssuanceLastModified().call() - self.availableHavvens = lambda acc: self.contract.functions.availableHavvens(acc).call() - self.lockedHavvens = lambda acc: self.contract.functions.lockedHavvens(acc).call() + self.maxIssuableNomins = lambda acc: self.contract.functions.maxIssuableNomins(acc).call() self.remainingIssuableNomins = lambda acc: self.contract.functions.remainingIssuableNomins(acc).call() + self.collateral = lambda acc: self.contract.functions.collateral(acc).call() + self.issuanceDraft = lambda acc: self.contract.functions.issuanceDraft(acc).call() + self.unavailableCollateral = lambda acc: self.contract.functions.unavailableCollateral(acc).call() + self.availableCollateral = lambda acc: self.contract.functions.availableCollateral(acc).call() + self.transferableHavvens = lambda acc: self.contract.functions.transferableHavvens(acc).call() # utility function - self.havValue = lambda havWei: self.contract.functions.havValue(havWei).call() + self.HAVtoUSD = lambda havWei: self.contract.functions.HAVtoUSD(havWei).call() + self.USDtoHAV = lambda usdWei: self.contract.functions.USDtoHAV(usdWei).call() # mutable functions self.setNomin = lambda sender, addr: mine_tx(self.contract.functions.setNomin(addr).transact({'from': sender}), "setNomin", self.contract_name) @@ -65,15 +70,15 @@ def __init__(self, contract, name): @staticmethod def issuance_data_current_balance_sum(issuance_data): - return balance_data[0] + return issuance_data[0] @staticmethod def issuance_data_last_average_balance(issuance_data): - return balance_data[1] + return issuance_data[1] @staticmethod def issuance_data_last_modified(issuance_data): - return balance_data[2] + return issuance_data[2] class PublicHavvenInterface(HavvenInterface): diff --git a/tests/contracts/PublicHavven.sol b/tests/contracts/PublicHavven.sol index 024f0cff00..b0ccd8c631 100644 --- a/tests/contracts/PublicHavven.sol +++ b/tests/contracts/PublicHavven.sol @@ -37,7 +37,7 @@ contract PublicHavven is Havven { * their havvens are escrowed, however the transfer would then * fail. This means that escrowed havvens are locked first, * and then the actual transferable ones. */ - require(nominsIssued[sender] == 0 || value <= availableHavvens(sender)); + require(nominsIssued[sender] == 0 || value <= transferableHavvens(sender)); /* Perform the transfer: if there is a problem, * an exception will be thrown in this call. */ tokenState.setBalanceOf(sender, safeSub(tokenState.balanceOf(sender), value)); diff --git a/tests/test_Court.py b/tests/test_Court.py index 23ad5061c2..8a83df7749 100644 --- a/tests/test_Court.py +++ b/tests/test_Court.py @@ -512,7 +512,7 @@ def test_beginMotion(self): self.havven.rolloverFeePeriodIfElapsed(DUMMY) self.havven.recomputeLastAverageBalance(voter, voter) self.havven.recomputeLastAverageBalance(insufficient_standing, insufficient_standing) - self.havven.recomputeLastAverageBalance(sufficient_standing,sufficient_standing) + self.havven.recomputeLastAverageBalance(sufficient_standing, sufficient_standing) # Must have at least 100 havvens to begin a confiscation motion. self.assertReverts(self.court.beginMotion, insufficient_standing, suspects[0]) tx_receipt = self.court.beginMotion(sufficient_standing, suspects[0]) @@ -822,7 +822,9 @@ def test_approveMotion(self): self.assertReverts(self.court.approveMotion, voter, motion_id) tx_receipt = self.court.approveMotion(owner, motion_id) - self.assertEqual(get_event_data_from_log(self.event_maps["Nomin"], tx_receipt.logs[0])['event'], "AccountFrozen") + self.assertEqual( + get_event_data_from_log(self.event_maps["Nomin"], tx_receipt.logs[0])['event'], "AccountFrozen" + ) self.assertEqual(get_event_data_from_log(self.event_maps["Nomin"], tx_receipt.logs[1])['event'], "Transfer") self.assertEqual(get_event_data_from_log(self.event_map, tx_receipt.logs[2])['event'], "MotionClosed") self.assertEqual(get_event_data_from_log(self.event_map, tx_receipt.logs[3])['event'], "MotionApproved") diff --git a/tests/test_Havven.py b/tests/test_Havven.py index 3c938534dd..083df5c72b 100644 --- a/tests/test_Havven.py +++ b/tests/test_Havven.py @@ -174,9 +174,9 @@ def test_constructor(self): ### # currentBalanceSum def test_currentBalanceSum(self): - #Testing the value of currentBalanceSum works as intended, - #Further testing involving this and fee collection will be done - #in scenario testing + # Testing the value of currentBalanceSum works as intended, + # Further testing involving this and fee collection will be done + # in scenario testing fee_period = self.havven.feePeriodDuration() delay = int(fee_period / 10) alice = fresh_account() @@ -332,7 +332,7 @@ def test_arithmeticSeriesBalance(self): self.havven.setIssuer(MASTER, alice, True) self.havven.issueNomins(alice, n * UNIT // 20) time_remaining = self.havven.feePeriodDuration() + self.havven.feePeriodStartTime() - block_time() - fast_forward(time_remaining + 5 ) + fast_forward(time_remaining + 5) self.havven.rolloverFeePeriodIfElapsed(MASTER) for _ in range(n): @@ -383,8 +383,8 @@ def test_averageBalanceSum(self): self.havven.recomputeLastAverageBalance(carol, carol) total_average = self.havven.issuanceLastAverageBalance(alice) + \ - self.havven.issuanceLastAverageBalance(bob) + \ - self.havven.issuanceLastAverageBalance(carol) + self.havven.issuanceLastAverageBalance(bob) + \ + self.havven.issuanceLastAverageBalance(carol) self.assertClose(UNIT, total_average, precision=3) @@ -669,7 +669,6 @@ def test_selfDestruct(self): # Check contract not exist self.assertEqual(W3.eth.getCode(address), b'\x00') - ### # Modifiers ### @@ -717,7 +716,7 @@ def test_event_PriceUpdated(self): tx.logs[0], "PriceUpdated", {"newPrice": 10 * UNIT, "timestamp": time}, - self.havven_proxy.address) + self.havven_proxy.address) def test_event_IssuanceRatioUpdated(self): new_ratio = UNIT // 12 @@ -725,10 +724,9 @@ def test_event_IssuanceRatioUpdated(self): self.assertEventEquals(self.event_map, tx.logs[0], "IssuanceRatioUpdated", {"newRatio": new_ratio}, - self.havven_proxy.address) + self.havven_proxy.address) def test_event_FeePeriodRollover(self): - time = block_time() fee_period = self.havven.feePeriodDuration() fast_forward(fee_period + 10) tx = self.havven.rolloverFeePeriodIfElapsed(MASTER) @@ -736,7 +734,7 @@ def test_event_FeePeriodRollover(self): self.assertEventEquals(self.event_map, tx.logs[0], "FeePeriodRollover", {"timestamp": time}, - self.havven_proxy.address) + self.havven_proxy.address) def test_event_FeePeriodDurationUpdated(self): new_duration = 19 * 24 * 60 * 60 @@ -744,7 +742,7 @@ def test_event_FeePeriodDurationUpdated(self): self.assertEventEquals(self.event_map, tx.logs[0], "FeePeriodDurationUpdated", {"duration": new_duration}, - self.havven_proxy.address) + self.havven_proxy.address) def test_event_FeesWithdrawn(self): issuer = fresh_account() @@ -764,7 +762,7 @@ def test_event_FeesWithdrawn(self): tx.logs[3], "FeesWithdrawn", {"account": issuer, "value": fee_rate}, - self.havven_proxy.address) + self.havven_proxy.address) def test_event_OracleUpdated(self): new_oracle = fresh_account() @@ -773,7 +771,7 @@ def test_event_OracleUpdated(self): self.assertEventEquals(self.event_map, tx.logs[0], "OracleUpdated", {"newOracle": new_oracle}, - self.havven_proxy.address) + self.havven_proxy.address) def test_event_NominUpdated(self): new_nomin = fresh_account() @@ -782,7 +780,7 @@ def test_event_NominUpdated(self): self.assertEventEquals(self.event_map, tx.logs[0], "NominUpdated", {"newNomin": new_nomin}, - self.havven_proxy.address) + self.havven_proxy.address) def test_event_EscrowUpdated(self): new_escrow = fresh_account() @@ -791,7 +789,7 @@ def test_event_EscrowUpdated(self): self.assertEventEquals(self.event_map, tx.logs[0], "EscrowUpdated", {"newEscrow": new_escrow}, - self.havven_proxy.address) + self.havven_proxy.address) def test_event_IssuersUpdated(self): new_issuer = fresh_account() @@ -801,11 +799,11 @@ def test_event_IssuersUpdated(self): tx.logs[0], "IssuersUpdated", {"account": new_issuer, "value": True}, - self.havven_proxy.address) + self.havven_proxy.address) tx = self.havven.setIssuer(MASTER, new_issuer, False) self.assertEventEquals(self.event_map, tx.logs[0], "IssuersUpdated", {"account": new_issuer, "value": False}, - self.havven_proxy.address) + self.havven_proxy.address) From f7b446ab2231f4623ee573fbe4304bfef3d1cc00 Mon Sep 17 00:00:00 2001 From: Anton Jurisevic Date: Fri, 22 Jun 2018 15:55:44 +1000 Subject: [PATCH 05/22] Unbreak issuance tests. --- tests/test_Issuance.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_Issuance.py b/tests/test_Issuance.py index 6e8d7a2601..f9c5c56fb8 100644 --- a/tests/test_Issuance.py +++ b/tests/test_Issuance.py @@ -113,7 +113,7 @@ def test_issue_against_escrowed(self): self.assertEqual(self.havven.balanceOf(alice), 0) self.assertEqual(self.nomin.balanceOf(alice), 100 * UNIT) - self.assertClose(self.havven.availableHavvens(alice) + 100 * UNIT / (self.havven.issuanceRatio() / UNIT), self.havven.totalSupply() // 2) + self.assertClose(self.havven.availableCollateral(alice) + 100 * UNIT / (self.havven.issuanceRatio() / UNIT), self.havven.totalSupply() // 2) def test_issuance_price_shift(self): alice = fresh_account() @@ -122,13 +122,13 @@ def test_issuance_price_shift(self): self.havven.setIssuer(MASTER, alice, True) self.havven_updatePrice(self.havven.oracle(), UNIT, self.havven.currentTime() + 1) self.havven.issueNomins(alice, 10 * UNIT) - self.assertEqual(self.havven.availableHavvens(alice), 800 * UNIT) + self.assertEqual(self.havven.availableCollateral(alice), 800 * UNIT) fast_forward(2) self.havven_updatePrice(self.havven.oracle(), 100 * UNIT, self.havven.currentTime() + 1) - self.assertEqual(self.havven.availableHavvens(alice), 998 * UNIT) + self.assertEqual(self.havven.availableCollateral(alice), 998 * UNIT) fast_forward(2) self.havven_updatePrice(self.havven.oracle(), int(0.01 * UNIT), self.havven.currentTime() + 1) - self.assertEqual(self.havven.availableHavvens(alice), 0) + self.assertEqual(self.havven.availableCollateral(alice), 0) self.assertReverts(self.havven.transfer, alice, MASTER, 1) From bdff9858f664e9c82b41d2cff76c08a0bb1b1a6e Mon Sep 17 00:00:00 2001 From: Anton Jurisevic Date: Mon, 25 Jun 2018 09:17:20 +1000 Subject: [PATCH 06/22] Add failing issuance stub tests. --- tests/test_Issuance.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/test_Issuance.py b/tests/test_Issuance.py index f9c5c56fb8..2ff26430f5 100644 --- a/tests/test_Issuance.py +++ b/tests/test_Issuance.py @@ -87,6 +87,9 @@ def setUpClass(cls): cls.fake_court = FakeCourtInterface(cls.fake_court_contract, "FakeCourt") cls.fake_court.setNomin(MASTER, cls.nomin_contract.address) + + def test_constructor_issuers(self): + self.assertTrue(False) def havven_updatePrice(self, sender, price, time): mine_tx(self.havven_contract.functions.updatePrice(price, time).transact({'from': sender}), 'updatePrice', 'Havven') @@ -174,4 +177,25 @@ def test_burn(self): self.assertEqual(self.havven.nominsIssued(alice), 0) self.assertEqual(self.nomin.balanceOf(alice), 0) + def test_transfer_locked_havvens(self): + self.assertTrue(False) + + def test_transferFrom_locked_havvens(self): + self.assertTrue(False) + + def test_collateral(self): + self.assertTrue(False) + + def test_issuanceDraft(self): + self.assertTrue(False) + + def test_unavailableCollateral(self): + self.assertTrue(False) + + def test_availableCollateral(self): + self.assertTrue(False) + + def test_transferableHavvens(self): + self.assertTrue(False) + From a2a6aa88a41f454f1b46bbed16c4cc496a33c41e Mon Sep 17 00:00:00 2001 From: Anton Jurisevic Date: Mon, 25 Jun 2018 13:10:53 +1000 Subject: [PATCH 07/22] Add input state to Feetoken (thus Nomin) constructor. --- contracts/ExternStateToken.sol | 5 +-- contracts/FeeToken.sol | 6 ++-- contracts/Havven.sol | 2 +- contracts/Nomin.sol | 5 +-- tests/contracts/PublicEST.sol | 7 ++-- tests/contracts/PublicFeeToken.sol | 9 ++++-- tests/contracts/PublicNomin.sol | 4 +-- tests/test_Court.py | 15 +++++---- tests/test_ExternStateToken.py | 44 +++++++++++++++++++------- tests/test_FeeCollection.py | 15 +++++---- tests/test_FeeToken.py | 51 +++++++++++++++++++++++------- tests/test_Havven.py | 15 +++++---- tests/test_HavvenEscrow.py | 17 ++++++---- tests/test_Issuance.py | 28 ++++++++++++---- tests/test_IssuanceController.py | 15 +++++---- tests/test_Nomin.py | 12 +++++-- tests/test_Proxy.py | 15 +++++---- 17 files changed, 178 insertions(+), 87 deletions(-) diff --git a/contracts/ExternStateToken.sol b/contracts/ExternStateToken.sol index 19f1dcc623..feba9fd780 100644 --- a/contracts/ExternStateToken.sol +++ b/contracts/ExternStateToken.sol @@ -57,8 +57,9 @@ contract ExternStateToken is SafeDecimalMath, SelfDestructible, Proxyable { * @param _tokenState The TokenState contract address. * @param _owner The owner of this contract. */ - constructor(address _proxy, string _name, string _symbol, uint _totalSupply, - TokenState _tokenState, address _owner) + constructor(address _proxy, TokenState _tokenState, + string _name, string _symbol, uint _totalSupply, + address _owner) SelfDestructible(_owner) Proxyable(_proxy, _owner) public diff --git a/contracts/FeeToken.sol b/contracts/FeeToken.sol index 144a0c2cff..c8b9d18a1e 100644 --- a/contracts/FeeToken.sol +++ b/contracts/FeeToken.sol @@ -63,10 +63,10 @@ contract FeeToken is ExternStateToken { * @param _feeAuthority The address which has the authority to withdraw fees from the accumulated pool. * @param _owner The owner of this contract. */ - constructor(address _proxy, string _name, string _symbol, uint _totalSupply, + constructor(address _proxy, TokenState _tokenState, string _name, string _symbol, uint _totalSupply, uint _transferFeeRate, address _feeAuthority, address _owner) - ExternStateToken(_proxy, _name, _symbol, _totalSupply, - new TokenState(_owner, address(this)), + ExternStateToken(_proxy, _tokenState, + _name, _symbol, _totalSupply, _owner) public { diff --git a/contracts/Havven.sol b/contracts/Havven.sol index e5e33108d5..9dbc4b3c67 100644 --- a/contracts/Havven.sol +++ b/contracts/Havven.sol @@ -212,7 +212,7 @@ contract Havven is ExternStateToken { */ constructor(address _proxy, TokenState _tokenState, address _owner, address _oracle, uint _price, address[] _issuers, uint[] _nominsIssued) - ExternStateToken(_proxy, TOKEN_NAME, TOKEN_SYMBOL, HAVVEN_SUPPLY, _tokenState, _owner) + ExternStateToken(_proxy, _tokenState, TOKEN_NAME, TOKEN_SYMBOL, HAVVEN_SUPPLY, _owner) public { oracle = _oracle; diff --git a/contracts/Nomin.sol b/contracts/Nomin.sol index 6a907fe388..935235eed2 100644 --- a/contracts/Nomin.sol +++ b/contracts/Nomin.sol @@ -57,8 +57,9 @@ contract Nomin is FeeToken { /* ========== CONSTRUCTOR ========== */ - constructor(address _proxy, Havven _havven, address _owner) - FeeToken(_proxy, TOKEN_NAME, TOKEN_SYMBOL, 0, // Zero nomins initially exist. + constructor(address _proxy, TokenState _tokenState, Havven _havven, address _owner) + FeeToken(_proxy, _tokenState, + TOKEN_NAME, TOKEN_SYMBOL, 0, // Zero nomins initially exist. TRANSFER_FEE_RATE, _havven, // The havven contract is the fee authority. _owner) diff --git a/tests/contracts/PublicEST.sol b/tests/contracts/PublicEST.sol index 69116da3cf..f6ffbbbd26 100644 --- a/tests/contracts/PublicEST.sol +++ b/tests/contracts/PublicEST.sol @@ -3,9 +3,10 @@ pragma solidity ^0.4.23; import "contracts/ExternStateToken.sol"; contract PublicEST is ExternStateToken { - constructor(address _proxy, string _name, string _symbol, uint _totalSupply, - TokenState _state, address _owner) - ExternStateToken(_proxy, _name, _symbol, _totalSupply, _state, _owner) + constructor(address _proxy, TokenState _tokenState, + string _name, string _symbol, uint _totalSupply, + address _owner) + ExternStateToken(_proxy, _tokenState, _name, _symbol, _totalSupply, _owner) public {} diff --git a/tests/contracts/PublicFeeToken.sol b/tests/contracts/PublicFeeToken.sol index 64cf193e3e..eb1471995b 100644 --- a/tests/contracts/PublicFeeToken.sol +++ b/tests/contracts/PublicFeeToken.sol @@ -3,9 +3,12 @@ pragma solidity ^0.4.23; import "contracts/FeeToken.sol"; contract PublicFeeToken is FeeToken { - constructor(address _proxy, string _name, string _symbol, uint _transferFeeRate, address _feeAuthority, - address _owner) - FeeToken(_proxy, _name, _symbol, 0, _transferFeeRate, _feeAuthority, _owner) + constructor(address _proxy, TokenState _tokenState, + string _name, string _symbol, uint _transferFeeRate, + address _feeAuthority, address _owner) + FeeToken(_proxy, _tokenState, + _name, _symbol, 0, _transferFeeRate, + _feeAuthority, _owner) public {} diff --git a/tests/contracts/PublicNomin.sol b/tests/contracts/PublicNomin.sol index 36422243e1..e6450488fc 100644 --- a/tests/contracts/PublicNomin.sol +++ b/tests/contracts/PublicNomin.sol @@ -12,8 +12,8 @@ contract PublicNomin is Nomin { uint constant MAX_TRANSFER_FEE_RATE = UNIT; // allow for 100% fees - constructor(address _proxy, Havven _havven, address _owner) - Nomin(_proxy, _havven, _owner) + constructor(address _proxy, TokenState _tokenState, Havven _havven, address _owner) + Nomin(_proxy, _tokenState, _havven, _owner) public {} function debugEmptyFeePool() diff --git a/tests/test_Court.py b/tests/test_Court.py index 8a83df7749..691eeb8589 100644 --- a/tests/test_Court.py +++ b/tests/test_Court.py @@ -53,21 +53,24 @@ def deployContracts(cls): proxied_havven = W3.eth.contract(address=havven_proxy.address, abi=havven_abi) proxied_nomin = W3.eth.contract(address=nomin_proxy.address, abi=nomin_abi) - tokenstate, _ = attempt_deploy(compiled, 'TokenState', - MASTER, [MASTER, MASTER]) + havven_tokenstate, _ = attempt_deploy(compiled, 'TokenState', + MASTER, [MASTER, MASTER]) + nomin_tokenstate, _ = attempt_deploy(compiled, 'TokenState', + MASTER, [MASTER, MASTER]) havven_contract, hvn_txr = attempt_deploy( - compiled, 'PublicHavven', MASTER, [havven_proxy.address, tokenstate.address, MASTER, MASTER, UNIT//2, [], []] + compiled, 'PublicHavven', MASTER, [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT//2, [], []] ) nomin_contract, nom_txr = attempt_deploy( - compiled, 'Nomin', MASTER, [nomin_proxy.address, havven_contract.address, MASTER] + compiled, 'Nomin', MASTER, [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, MASTER] ) court_contract, court_txr = attempt_deploy( compiled, 'PublicCourt', MASTER, [havven_contract.address, nomin_contract.address, MASTER] ) mine_txs([ - tokenstate.functions.setBalanceOf(havven_contract.address, 100000000 * UNIT).transact({'from': MASTER}), - tokenstate.functions.setAssociatedContract(havven_contract.address).transact({'from': MASTER}), + havven_tokenstate.functions.setBalanceOf(havven_contract.address, 100000000 * UNIT).transact({'from': MASTER}), + havven_tokenstate.functions.setAssociatedContract(havven_contract.address).transact({'from': MASTER}), + nomin_tokenstate.functions.setAssociatedContract(nomin_contract.address).transact({'from': MASTER}), havven_proxy.functions.setTarget(havven_contract.address).transact({'from': MASTER}), nomin_proxy.functions.setTarget(nomin_contract.address).transact({'from': MASTER}), havven_contract.functions.setNomin(nomin_contract.address).transact({'from': MASTER}), diff --git a/tests/test_ExternStateToken.py b/tests/test_ExternStateToken.py index 5828ebb6d8..3d782a278e 100644 --- a/tests/test_ExternStateToken.py +++ b/tests/test_ExternStateToken.py @@ -1,14 +1,15 @@ from utils.deployutils import ( W3, UNIT, MASTER, DUMMY, fresh_account, fresh_accounts, - attempt_deploy, - mine_txs, take_snapshot, restore_snapshot + attempt_deploy, mine_tx, mine_txs, + take_snapshot, restore_snapshot ) from utils.testutils import ( HavvenTestCase, ZERO_ADDRESS, generate_topic_event_map, get_event_data_from_log ) from tests.contract_interfaces.extern_state_token_interface import ExternStateTokenInterface +from tests.contract_interfaces.token_state_interface import TokenStateInterface def setUpModule(): @@ -46,7 +47,7 @@ def deploy_contracts(cls): token_contract, construction_txr = attempt_deploy( compiled, 'PublicEST', MASTER, - [proxy_contract.address, "Test Token", "TEST", 1000 * UNIT, tokenstate.address, MASTER] + [proxy_contract.address, tokenstate.address, "Test Token", "TEST", 1000 * UNIT, MASTER] ) token_abi = compiled['PublicEST']['abi'] @@ -76,16 +77,37 @@ def test_constructor(self): self.assertEqual(self.token.tokenState(), self.tokenstate.address) self.assertEqual(self.tokenstate.functions.associatedContract().call(), self.token_contract.address) - def test_provide_state(self): - tokenstate, _ = attempt_deploy(self.compiled, 'TokenState', + def test_change_state(self): + lucky_one = fresh_account() + + # Deploy contract and old tokenstate + _old_tokenstate, _ = attempt_deploy(self.compiled, 'TokenState', MASTER, - [MASTER, self.token_contract.address]) - token, _ = attempt_deploy(self.compiled, 'ExternStateToken', + [MASTER, MASTER]) + old_tokenstate = TokenStateInterface(_old_tokenstate, 'TokenState') + _token, _ = attempt_deploy(self.compiled, 'ExternStateToken', MASTER, - [self.proxy.address, "Test Token", "TEST", - 1000 * UNIT, - tokenstate.address, DUMMY]) - self.assertEqual(token.functions.tokenState().call(), tokenstate.address) + [self.proxy.address, old_tokenstate.contract.address, + "Test Token", "TEST", 1000 * UNIT, MASTER]) + token = ExternStateTokenInterface(_token, 'ExternStateToken') + mine_txs([self.proxy.functions.setTarget(token.contract.address).transact({"from": MASTER})]) + + old_tokenstate.setAssociatedContract(MASTER, token.contract.address) + self.assertEqual(token.balanceOf(lucky_one), 0) + self.assertEqual(old_tokenstate.balanceOf(lucky_one), 0) + + # Deploy new tokenstate and swap it out with the existing one. + _new_tokenstate, _ = attempt_deploy(self.compiled, 'TokenState', + MASTER, + [MASTER, MASTER]) + new_tokenstate = TokenStateInterface(_new_tokenstate, 'TokenState') + new_tokenstate.setBalanceOf(MASTER, lucky_one, UNIT) + new_tokenstate.setAssociatedContract(MASTER, token.contract.address) + token.setTokenState(MASTER, new_tokenstate.contract.address) + + self.assertEqual(token.tokenState(), new_tokenstate.contract.address) + self.assertEqual(token.balanceOf(lucky_one), UNIT) + self.assertEqual(new_tokenstate.balanceOf(lucky_one), UNIT) def test_getSetTokenState(self): new_tokenstate = fresh_account() diff --git a/tests/test_FeeCollection.py b/tests/test_FeeCollection.py index 86a4ae0030..dde9abab7d 100644 --- a/tests/test_FeeCollection.py +++ b/tests/test_FeeCollection.py @@ -42,21 +42,24 @@ def deployContracts(cls): nomin_proxy, _ = attempt_deploy(compiled, 'Proxy', MASTER, [MASTER]) proxied_havven = W3.eth.contract(address=havven_proxy.address, abi=compiled['PublicHavven']['abi']) proxied_nomin = W3.eth.contract(address=nomin_proxy.address, abi=compiled['PublicNomin']['abi']) - tokenstate, _ = attempt_deploy(compiled, 'TokenState', - MASTER, [MASTER, MASTER]) + havven_tokenstate, _ = attempt_deploy(compiled, 'TokenState', + MASTER, [MASTER, MASTER]) + nomin_tokenstate, _ = attempt_deploy(compiled, 'TokenState', + MASTER, [MASTER, MASTER]) havven_contract, hvn_txr = attempt_deploy(compiled, 'PublicHavven', - MASTER, [havven_proxy.address, tokenstate.address, MASTER, MASTER, UNIT//2, [], []]) + MASTER, [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT//2, [], []]) nomin_contract, nom_txr = attempt_deploy(compiled, 'PublicNomin', MASTER, - [nomin_proxy.address, havven_contract.address, MASTER]) + [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, MASTER]) court_contract, court_txr = attempt_deploy(compiled, 'FakeCourt', MASTER, [havven_contract.address, nomin_contract.address, MASTER]) # Hook up each of those contracts to each other - mine_txs([tokenstate.functions.setBalanceOf(havven_contract.address, 100000000 * UNIT).transact({'from': MASTER}), - tokenstate.functions.setAssociatedContract(havven_contract.address).transact({'from': MASTER}), + mine_txs([havven_tokenstate.functions.setBalanceOf(havven_contract.address, 100000000 * UNIT).transact({'from': MASTER}), + havven_tokenstate.functions.setAssociatedContract(havven_contract.address).transact({'from': MASTER}), + nomin_tokenstate.functions.setAssociatedContract(nomin_contract.address).transact({'from': MASTER}), havven_proxy.functions.setTarget(havven_contract.address).transact({'from': MASTER}), nomin_proxy.functions.setTarget(nomin_contract.address).transact({'from': MASTER}), havven_contract.functions.setNomin(nomin_contract.address).transact({'from': MASTER}), diff --git a/tests/test_FeeToken.py b/tests/test_FeeToken.py index c0e43234de..a3f272beea 100644 --- a/tests/test_FeeToken.py +++ b/tests/test_FeeToken.py @@ -8,6 +8,7 @@ generate_topic_event_map, get_event_data_from_log ) from tests.contract_interfaces.fee_token_interface import PublicFeeTokenInterface +from tests.contract_interfaces.token_state_interface import TokenStateInterface def setUpModule(): @@ -43,17 +44,17 @@ def deployContracts(cls): ) proxied_feetoken = W3.eth.contract(address=proxy.address, abi=feetoken_abi) - feetoken_event_dict = generate_topic_event_map(feetoken_abi) - feetoken_contract, construction_txr = attempt_deploy( - compiled, "PublicFeeToken", MASTER, - [proxy.address, "Test Fee Token", "FEE", UNIT // 20, MASTER, MASTER] - ) - feestate, txr = attempt_deploy( compiled, "TokenState", MASTER, [MASTER, MASTER] ) + feetoken_event_dict = generate_topic_event_map(feetoken_abi) + feetoken_contract, construction_txr = attempt_deploy( + compiled, "PublicFeeToken", MASTER, + [proxy.address, feestate.address, "Test Fee Token", "FEE", UNIT // 20, MASTER, MASTER] + ) + mine_txs([ proxy.functions.setTarget(feetoken_contract.address).transact({'from': MASTER}), feestate.functions.setBalanceOf(DUMMY, 1000 * UNIT).transact({'from': MASTER}), @@ -87,12 +88,38 @@ def test_constructor(self): self.assertEqual(self.feetoken.tokenState(), self.feestate.address) self.assertEqual(self.feestate.functions.associatedContract().call(), self.feetoken_contract.address) - def test_provide_tokenstate(self): - feetoken, _ = attempt_deploy(self.compiled, 'FeeToken', - MASTER, - [self.proxy.address, "Test Fee Token", "FEE", 0, - UNIT // 20, self.fee_authority, DUMMY]) - self.assertNotEqual(feetoken.functions.tokenState().call(), ZERO_ADDRESS) + def test_change_state(self): + lucky_one = fresh_account() + + # Deploy contract and old tokenstate + _old_tokenstate, _ = attempt_deploy(self.compiled, 'TokenState', + MASTER, + [MASTER, MASTER]) + old_tokenstate = TokenStateInterface(_old_tokenstate, 'TokenState') + _token, _ = attempt_deploy(self.compiled, 'FeeToken', + MASTER, + [self.proxy.address, old_tokenstate.contract.address, + "Test Fee Token", "FEE", 0, UNIT // 20, self.fee_authority, + MASTER]) + token = PublicFeeTokenInterface(_token, 'FeeToken') + mine_txs([self.proxy.functions.setTarget(token.contract.address).transact({"from": MASTER})]) + + old_tokenstate.setAssociatedContract(MASTER, token.contract.address) + self.assertEqual(token.balanceOf(lucky_one), 0) + self.assertEqual(old_tokenstate.balanceOf(lucky_one), 0) + + # Deploy new tokenstate and swap it out with the existing one. + _new_tokenstate, _ = attempt_deploy(self.compiled, 'TokenState', + MASTER, + [MASTER, MASTER]) + new_tokenstate = TokenStateInterface(_new_tokenstate, 'TokenState') + new_tokenstate.setBalanceOf(MASTER, lucky_one, UNIT) + new_tokenstate.setAssociatedContract(MASTER, token.contract.address) + token.setTokenState(MASTER, new_tokenstate.contract.address) + + self.assertEqual(token.tokenState(), new_tokenstate.contract.address) + self.assertEqual(token.balanceOf(lucky_one), UNIT) + self.assertEqual(new_tokenstate.balanceOf(lucky_one), UNIT) def test_getSetOwner(self): owner = self.feetoken.owner() diff --git a/tests/test_Havven.py b/tests/test_Havven.py index 083df5c72b..c7edc89a67 100644 --- a/tests/test_Havven.py +++ b/tests/test_Havven.py @@ -50,13 +50,15 @@ def deployContracts(cls): proxied_havven = W3.eth.contract(address=havven_proxy.address, abi=compiled['PublicHavven']['abi']) proxied_nomin = W3.eth.contract(address=nomin_proxy.address, abi=compiled['Nomin']['abi']) - tokenstate, _ = attempt_deploy(compiled, 'TokenState', - MASTER, [MASTER, MASTER]) - havven_contract, hvn_txr = attempt_deploy(compiled, 'PublicHavven', MASTER, [havven_proxy.address, tokenstate.address, MASTER, MASTER, UNIT//2, [], []]) + havven_tokenstate, _ = attempt_deploy(compiled, 'TokenState', + MASTER, [MASTER, MASTER]) + nomin_tokenstate, _ = attempt_deploy(compiled, 'TokenState', + MASTER, [MASTER, MASTER]) + havven_contract, hvn_txr = attempt_deploy(compiled, 'PublicHavven', MASTER, [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT//2, [], []]) hvn_block = W3.eth.blockNumber nomin_contract, nom_txr = attempt_deploy(compiled, 'Nomin', MASTER, - [nomin_proxy.address, havven_contract.address, MASTER]) + [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, MASTER]) court_contract, court_txr = attempt_deploy(compiled, 'Court', MASTER, [havven_contract.address, nomin_contract.address, @@ -67,8 +69,9 @@ def deployContracts(cls): # Hook up each of those contracts to each other mine_txs([ - tokenstate.functions.setBalanceOf(havven_contract.address, 100000000 * UNIT).transact({'from': MASTER}), - tokenstate.functions.setAssociatedContract(havven_contract.address).transact({'from': MASTER}), + havven_tokenstate.functions.setBalanceOf(havven_contract.address, 100000000 * UNIT).transact({'from': MASTER}), + havven_tokenstate.functions.setAssociatedContract(havven_contract.address).transact({'from': MASTER}), + nomin_tokenstate.functions.setAssociatedContract(nomin_contract.address).transact({'from': MASTER}), havven_proxy.functions.setTarget(havven_contract.address).transact({'from': MASTER}), nomin_proxy.functions.setTarget(nomin_contract.address).transact({'from': MASTER}), havven_contract.functions.setNomin(nomin_contract.address).transact({'from': MASTER}), diff --git a/tests/test_HavvenEscrow.py b/tests/test_HavvenEscrow.py index 918e1f353f..d3f2314e3b 100644 --- a/tests/test_HavvenEscrow.py +++ b/tests/test_HavvenEscrow.py @@ -52,14 +52,16 @@ def deployContracts(cls): proxied_havven = W3.eth.contract(address=havven_proxy.address, abi=cls.compiled['PublicHavven']['abi']) proxied_nomin = W3.eth.contract(address=nomin_proxy.address, abi=cls.compiled['PublicNomin']['abi']) - tokenstate, _ = attempt_deploy(cls.compiled, 'TokenState', - MASTER, [MASTER, MASTER]) - havven_contract, hvn_txr = attempt_deploy(cls.compiled, 'PublicHavven', MASTER, [havven_proxy.address, tokenstate.address, MASTER, MASTER, UNIT//2, [], []]) + havven_tokenstate, _ = attempt_deploy(cls.compiled, 'TokenState', + MASTER, [MASTER, MASTER]) + nomin_tokenstate, _ = attempt_deploy(cls.compiled, 'TokenState', + MASTER, [MASTER, MASTER]) + havven_contract, hvn_txr = attempt_deploy(cls.compiled, 'PublicHavven', MASTER, [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT//2, [], []]) hvn_block = W3.eth.blockNumber nomin_contract, nom_txr = attempt_deploy(cls.compiled, 'PublicNomin', MASTER, - [nomin_proxy.address, havven_contract.address, MASTER]) + [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, MASTER]) court_contract, court_txr = attempt_deploy(cls.compiled, 'Court', MASTER, [havven_contract.address, nomin_contract.address, @@ -69,8 +71,9 @@ def deployContracts(cls): [MASTER, havven_contract.address]) # Hook up each of those contracts to each other - mine_txs([tokenstate.functions.setBalanceOf(havven_contract.address, 100000000 * UNIT).transact({'from': MASTER}), - tokenstate.functions.setAssociatedContract(havven_contract.address).transact({'from': MASTER}), + mine_txs([havven_tokenstate.functions.setBalanceOf(havven_contract.address, 100000000 * UNIT).transact({'from': MASTER}), + havven_tokenstate.functions.setAssociatedContract(havven_contract.address).transact({'from': MASTER}), + nomin_tokenstate.functions.setAssociatedContract(nomin_contract.address).transact({'from': MASTER}), havven_proxy.functions.setTarget(havven_contract.address).transact({'from': MASTER}), nomin_proxy.functions.setTarget(nomin_contract.address).transact({'from': MASTER}), havven_contract.functions.setNomin(nomin_contract.address).transact({'from': MASTER}), @@ -82,7 +85,7 @@ def deployContracts(cls): havven_event_dict = generate_topic_event_map(cls.compiled['PublicHavven']['abi']) print("\nDeployment complete.\n") - return havven_proxy, proxied_havven, tokenstate, nomin_proxy, proxied_nomin, havven_contract, nomin_contract, court_contract, escrow_contract, hvn_block, escrow_event_dict, havven_event_dict + return havven_proxy, proxied_havven, havven_tokenstate, nomin_proxy, proxied_nomin, havven_contract, nomin_contract, court_contract, escrow_contract, hvn_block, escrow_event_dict, havven_event_dict @classmethod def setUpClass(cls): diff --git a/tests/test_Issuance.py b/tests/test_Issuance.py index 2ff26430f5..1abda088f0 100644 --- a/tests/test_Issuance.py +++ b/tests/test_Issuance.py @@ -46,14 +46,16 @@ def deployContracts(cls): proxied_havven = W3.eth.contract(address=havven_proxy.address, abi=compiled['PublicHavven']['abi']) proxied_nomin = W3.eth.contract(address=nomin_proxy.address, abi=compiled['PublicNomin']['abi']) - tokenstate, _ = attempt_deploy(compiled, 'TokenState', - MASTER, [MASTER, MASTER]) - havven_contract, hvn_txr = attempt_deploy(compiled, 'PublicHavven', MASTER, - [havven_proxy.address, tokenstate.address, MASTER, MASTER, UNIT//2, [], []]) + havven_tokenstate, _ = attempt_deploy(compiled, 'TokenState', + MASTER, [MASTER, MASTER]) + nomin_tokenstate, _ = attempt_deploy(compiled, 'TokenState', + MASTER, [MASTER, MASTER]) + havven_contract, hvn_txr = attempt_deploy(compiled, 'PublicHavven', MASTER, + [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT//2, [], []]) nomin_contract, nom_txr = attempt_deploy(compiled, 'PublicNomin', MASTER, - [nomin_proxy.address, havven_contract.address, MASTER]) + [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, MASTER]) court_contract, court_txr = attempt_deploy(compiled, 'FakeCourt', MASTER, [havven_contract.address, nomin_contract.address, @@ -63,8 +65,9 @@ def deployContracts(cls): [MASTER, havven_contract.address]) # Hook up each of those contracts to each other - mine_txs([tokenstate.functions.setBalanceOf(havven_contract.address, 100000000 * UNIT).transact({'from': MASTER}), - tokenstate.functions.setAssociatedContract(havven_contract.address).transact({'from': MASTER}), + mine_txs([havven_tokenstate.functions.setBalanceOf(havven_contract.address, 100000000 * UNIT).transact({'from': MASTER}), + havven_tokenstate.functions.setAssociatedContract(havven_contract.address).transact({'from': MASTER}), + nomin_tokenstate.functions.setAssociatedContract(nomin_contract.address).transact({'from': MASTER}), havven_proxy.functions.setTarget(havven_contract.address).transact({'from': MASTER}), nomin_proxy.functions.setTarget(nomin_contract.address).transact({'from': MASTER}), havven_contract.functions.setNomin(nomin_contract.address).transact({'from': MASTER}), @@ -179,6 +182,17 @@ def test_burn(self): def test_transfer_locked_havvens(self): self.assertTrue(False) + alice, bob = fresh_accounts(2) + self.havven.endow(MASTER, alice, 500 * UNIT) + + self.havven.endow(MASTER, self.escrow.contract.address, 500 * UNIT) + self.escrow.appendVestingEntry(MASTER, alice, block_time() + 10000000, 500 * UNIT) + self.havven.setIssuer(MASTER, alice, True) + self.havven_updatePrice(self.havven.oracle(), UNIT, self.havven.currentTime() + 1) + self.havven.setIssuanceRatio(MASTER, UNIT) + + self.havven.issueNomins(alice, 100 * UNIT) + def test_transferFrom_locked_havvens(self): self.assertTrue(False) diff --git a/tests/test_IssuanceController.py b/tests/test_IssuanceController.py index 210f1333ec..b0cbebc62a 100644 --- a/tests/test_IssuanceController.py +++ b/tests/test_IssuanceController.py @@ -47,18 +47,21 @@ def deployContracts(cls): proxied_havven = W3.eth.contract(address=havven_proxy.address, abi=havven_abi) proxied_nomin = W3.eth.contract(address=nomin_proxy.address, abi=nomin_abi) - tokenstate, _ = attempt_deploy(compiled, 'TokenState', - MASTER, [MASTER, MASTER]) + havven_tokenstate, _ = attempt_deploy(compiled, 'TokenState', + MASTER, [MASTER, MASTER]) + nomin_tokenstate, _ = attempt_deploy(compiled, 'TokenState', + MASTER, [MASTER, MASTER]) havven_contract, hvn_txr = attempt_deploy( - compiled, 'PublicHavven', MASTER, [havven_proxy.address, tokenstate.address, MASTER, MASTER, UNIT//2, [], []] + compiled, 'PublicHavven', MASTER, [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT//2, [], []] ) nomin_contract, nom_txr = attempt_deploy( - compiled, 'PublicNomin', MASTER, [nomin_proxy.address, havven_contract.address, MASTER] + compiled, 'PublicNomin', MASTER, [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, MASTER] ) mine_txs([ - tokenstate.functions.setBalanceOf(havven_contract.address, 100000000 * UNIT).transact({'from': MASTER}), - tokenstate.functions.setAssociatedContract(havven_contract.address).transact({'from': MASTER}), + havven_tokenstate.functions.setBalanceOf(havven_contract.address, 100000000 * UNIT).transact({'from': MASTER}), + havven_tokenstate.functions.setAssociatedContract(havven_contract.address).transact({'from': MASTER}), + nomin_tokenstate.functions.setAssociatedContract(nomin_contract.address).transact({'from': MASTER}), havven_proxy.functions.setTarget(havven_contract.address).transact({'from': MASTER}), nomin_proxy.functions.setTarget(nomin_contract.address).transact({'from': MASTER}), havven_contract.functions.setNomin(nomin_contract.address).transact({'from': MASTER}), diff --git a/tests/test_Nomin.py b/tests/test_Nomin.py index 652aec3911..14d9842ce5 100644 --- a/tests/test_Nomin.py +++ b/tests/test_Nomin.py @@ -41,8 +41,12 @@ def deployContracts(cls): proxied_havven = W3.eth.contract(address=havven_proxy.address, abi=compiled['Havven']['abi']) proxied_nomin = W3.eth.contract(address=nomin_proxy.address, abi=compiled['PublicNomin']['abi']) + nomin_state, txr = attempt_deploy( + compiled, "TokenState", MASTER, + [MASTER, MASTER] + ) nomin_contract, _ = attempt_deploy( - compiled, 'PublicNomin', MASTER, [nomin_proxy.address, MASTER, MASTER] + compiled, 'PublicNomin', MASTER, [nomin_proxy.address, nomin_state.address, MASTER, MASTER] ) havven_contract, _ = attempt_deploy( @@ -52,6 +56,7 @@ def deployContracts(cls): fake_court, _ = attempt_deploy(compiled, 'FakeCourt', MASTER, []) mine_txs([ + nomin_state.functions.setAssociatedContract(nomin_contract.address).transact({'from': MASTER}), havven_proxy.functions.setTarget(havven_contract.address).transact({'from': MASTER}), nomin_proxy.functions.setTarget(nomin_contract.address).transact({'from': MASTER}), havven_contract.functions.setNomin(nomin_contract.address).transact({'from': MASTER}), @@ -59,11 +64,11 @@ def deployContracts(cls): nomin_contract.functions.setHavven(havven_contract.address).transact({'from': MASTER}) ]) - return havven_proxy, proxied_havven, nomin_proxy, proxied_nomin, nomin_contract, havven_contract, fake_court + return havven_proxy, proxied_havven, nomin_proxy, proxied_nomin, nomin_contract, havven_contract, fake_court, nomin_state @classmethod def setUpClass(cls): - cls.havven_proxy, cls.proxied_havven, cls.nomin_proxy, cls.proxied_nomin, cls.nomin_contract, cls.havven_contract, cls.fake_court_contract = cls.deployContracts() + cls.havven_proxy, cls.proxied_havven, cls.nomin_proxy, cls.proxied_nomin, cls.nomin_contract, cls.havven_contract, cls.fake_court_contract, cls.nomin_state = cls.deployContracts() cls.nomin_event_dict = cls.event_maps['Nomin'] @@ -93,6 +98,7 @@ def test_constructor(self): self.assertEqual(self.nomin.transferFeeRate(), 15 * UNIT // 10000) self.assertEqual(self.nomin.feeAuthority(), self.nomin.havven()) self.assertEqual(self.nomin.decimals(), 18) + self.assertEqual(self.nomin.tokenState(), self.nomin_state.address) def test_setOwner(self): pre_owner = self.nomin.owner() diff --git a/tests/test_Proxy.py b/tests/test_Proxy.py index 3ec0589255..ab72131b23 100644 --- a/tests/test_Proxy.py +++ b/tests/test_Proxy.py @@ -44,19 +44,20 @@ def deployContracts(): proxied_feetoken = W3.eth.contract(address=proxy.address, abi=feetoken_abi) feetoken_event_dict = generate_topic_event_map(feetoken_abi) + + feestate, txr = attempt_deploy( + compiled, "TokenState", MASTER, + [MASTER, MASTER] + ) + feetoken_contract_1, construction_txr_1 = attempt_deploy( compiled, "PublicFeeToken", MASTER, - [proxy.address, "Test Fee Token", "FEE", UNIT // 20, MASTER, MASTER] + [proxy.address, feestate.address, "Test Fee Token", "FEE", UNIT // 20, MASTER, MASTER] ) feetoken_contract_2, construction_txr_2 = attempt_deploy( compiled, "PublicFeeToken", MASTER, - [proxy.address, "Test Fee Token 2", "FEE", UNIT // 20, MASTER, MASTER] - ) - - feestate, txr = attempt_deploy( - compiled, "TokenState", MASTER, - [MASTER, MASTER] + [proxy.address, feestate.address, "Test Fee Token 2", "FEE", UNIT // 20, MASTER, MASTER] ) mine_txs([ From 8543b388c74b014ae9d69e3ea8df2406fedf6579 Mon Sep 17 00:00:00 2001 From: Anton Jurisevic Date: Wed, 27 Jun 2018 14:39:33 +1000 Subject: [PATCH 08/22] Fee address change and added total supply to fee tokens. --- contracts/FeeToken.sol | 16 +++++++++------- contracts/Nomin.sol | 6 ++++-- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/contracts/FeeToken.sol b/contracts/FeeToken.sol index c8b9d18a1e..8e5090083d 100644 --- a/contracts/FeeToken.sol +++ b/contracts/FeeToken.sol @@ -49,6 +49,8 @@ contract FeeToken is ExternStateToken { uint constant MAX_TRANSFER_FEE_RATE = UNIT / 10; /* The address with the authority to distribute fees. */ address public feeAuthority; + /* The address that fees will be pooled in. */ + address constant FEE_ADDRESS = 0xfeefeefeefeefeefeefeefeefeefeefeefeefeef; /* ========== CONSTRUCTOR ========== */ @@ -158,7 +160,7 @@ contract FeeToken is ExternStateToken { view returns (uint) { - return tokenState.balanceOf(address(this)); + return tokenState.balanceOf(FEE_ADDRESS); } /* ========== MUTATIVE FUNCTIONS ========== */ @@ -178,11 +180,11 @@ contract FeeToken is ExternStateToken { /* Insufficient balance will be handled by the safe subtraction. */ tokenState.setBalanceOf(from, safeSub(tokenState.balanceOf(from), safeAdd(amount, fee))); tokenState.setBalanceOf(to, safeAdd(tokenState.balanceOf(to), amount)); - tokenState.setBalanceOf(address(this), safeAdd(tokenState.balanceOf(address(this)), fee)); + tokenState.setBalanceOf(FEE_ADDRESS, safeAdd(tokenState.balanceOf(FEE_ADDRESS), fee)); /* Emit events for both the transfer itself and the fee. */ emitTransfer(from, to, amount); - emitTransfer(from, address(this), fee); + emitTransfer(from, FEE_ADDRESS, fee); return true; } @@ -264,11 +266,11 @@ contract FeeToken is ExternStateToken { } /* Safe subtraction ensures an exception is thrown if the balance is insufficient. */ - tokenState.setBalanceOf(address(this), safeSub(tokenState.balanceOf(address(this)), value)); + tokenState.setBalanceOf(FEE_ADDRESS, safeSub(tokenState.balanceOf(FEE_ADDRESS), value)); tokenState.setBalanceOf(account, safeAdd(tokenState.balanceOf(account), value)); emitFeesWithdrawn(account, value); - emitTransfer(address(this), account, value); + emitTransfer(FEE_ADDRESS, account, value); return true; } @@ -288,10 +290,10 @@ contract FeeToken is ExternStateToken { /* safeSub ensures the donor has sufficient balance. */ tokenState.setBalanceOf(sender, safeSub(balance, n)); - tokenState.setBalanceOf(address(this), safeAdd(tokenState.balanceOf(address(this)), n)); + tokenState.setBalanceOf(FEE_ADDRESS, safeAdd(tokenState.balanceOf(address(this)), n)); emitFeesDonated(sender, n); - emitTransfer(sender, address(this), n); + emitTransfer(sender, FEE_ADDRESS, n); return true; } diff --git a/contracts/Nomin.sol b/contracts/Nomin.sol index 935235eed2..5083a01f2a 100644 --- a/contracts/Nomin.sol +++ b/contracts/Nomin.sol @@ -57,9 +57,11 @@ contract Nomin is FeeToken { /* ========== CONSTRUCTOR ========== */ - constructor(address _proxy, TokenState _tokenState, Havven _havven, address _owner) + constructor(address _proxy, TokenState _tokenState, Havven _havven, + uint _totalSupply, + address _owner) FeeToken(_proxy, _tokenState, - TOKEN_NAME, TOKEN_SYMBOL, 0, // Zero nomins initially exist. + TOKEN_NAME, TOKEN_SYMBOL, _totalSupply, TRANSFER_FEE_RATE, _havven, // The havven contract is the fee authority. _owner) From 5002e36725c83015725c00206b7620c2effb0244 Mon Sep 17 00:00:00 2001 From: Anton Jurisevic Date: Wed, 27 Jun 2018 17:10:01 +1000 Subject: [PATCH 09/22] Fix lingering issues from changing fee address. --- contracts/FeeToken.sol | 4 ++-- contracts/Nomin.sol | 4 ++-- tests/contracts/PublicFeeToken.sol | 5 +++-- tests/contracts/PublicNomin.sol | 14 ++++++++------ tests/test_Court.py | 2 +- tests/test_FeeCollection.py | 2 +- tests/test_FeeToken.py | 12 ++++++------ tests/test_Havven.py | 5 ++++- tests/test_HavvenEscrow.py | 2 +- tests/test_Issuance.py | 2 +- tests/test_IssuanceController.py | 2 +- tests/test_Nomin.py | 22 +++++++++++----------- 12 files changed, 41 insertions(+), 35 deletions(-) diff --git a/contracts/FeeToken.sol b/contracts/FeeToken.sol index 8e5090083d..ba295256f3 100644 --- a/contracts/FeeToken.sol +++ b/contracts/FeeToken.sol @@ -50,7 +50,7 @@ contract FeeToken is ExternStateToken { /* The address with the authority to distribute fees. */ address public feeAuthority; /* The address that fees will be pooled in. */ - address constant FEE_ADDRESS = 0xfeefeefeefeefeefeefeefeefeefeefeefeefeef; + address public constant FEE_ADDRESS = 0xfeefeefeefeefeefeefeefeefeefeefeefeefeef; /* ========== CONSTRUCTOR ========== */ @@ -290,7 +290,7 @@ contract FeeToken is ExternStateToken { /* safeSub ensures the donor has sufficient balance. */ tokenState.setBalanceOf(sender, safeSub(balance, n)); - tokenState.setBalanceOf(FEE_ADDRESS, safeAdd(tokenState.balanceOf(address(this)), n)); + tokenState.setBalanceOf(FEE_ADDRESS, safeAdd(tokenState.balanceOf(FEE_ADDRESS), n)); emitFeesDonated(sender, n); emitTransfer(sender, FEE_ADDRESS, n); diff --git a/contracts/Nomin.sol b/contracts/Nomin.sol index 5083a01f2a..1b38649443 100644 --- a/contracts/Nomin.sol +++ b/contracts/Nomin.sol @@ -160,11 +160,11 @@ contract Nomin is FeeToken { // Confiscate the balance in the account and freeze it. uint balance = tokenState.balanceOf(target); - tokenState.setBalanceOf(address(this), safeAdd(tokenState.balanceOf(address(this)), balance)); + tokenState.setBalanceOf(FEE_ADDRESS, safeAdd(tokenState.balanceOf(FEE_ADDRESS), balance)); tokenState.setBalanceOf(target, 0); frozen[target] = true; emitAccountFrozen(target, balance); - emitTransfer(target, address(this), balance); + emitTransfer(target, FEE_ADDRESS, balance); } /* The owner may allow a previously-frozen contract to once diff --git a/tests/contracts/PublicFeeToken.sol b/tests/contracts/PublicFeeToken.sol index eb1471995b..58bec5ffe0 100644 --- a/tests/contracts/PublicFeeToken.sol +++ b/tests/contracts/PublicFeeToken.sol @@ -4,10 +4,11 @@ import "contracts/FeeToken.sol"; contract PublicFeeToken is FeeToken { constructor(address _proxy, TokenState _tokenState, - string _name, string _symbol, uint _transferFeeRate, + string _name, string _symbol, uint _totalSupply, + uint _transferFeeRate, address _feeAuthority, address _owner) FeeToken(_proxy, _tokenState, - _name, _symbol, 0, _transferFeeRate, + _name, _symbol, _totalSupply, _transferFeeRate, _feeAuthority, _owner) public {} diff --git a/tests/contracts/PublicNomin.sol b/tests/contracts/PublicNomin.sol index e6450488fc..1f0216e4a4 100644 --- a/tests/contracts/PublicNomin.sol +++ b/tests/contracts/PublicNomin.sol @@ -12,14 +12,16 @@ contract PublicNomin is Nomin { uint constant MAX_TRANSFER_FEE_RATE = UNIT; // allow for 100% fees - constructor(address _proxy, TokenState _tokenState, Havven _havven, address _owner) - Nomin(_proxy, _tokenState, _havven, _owner) + constructor(address _proxy, TokenState _tokenState, Havven _havven, + uint _totalSupply, + address _owner) + Nomin(_proxy, _tokenState, _havven, _totalSupply, _owner) public {} function debugEmptyFeePool() public { - tokenState.setBalanceOf(address(this), 0); + tokenState.setBalanceOf(FEE_ADDRESS, 0); } function debugFreezeAccount(address target) @@ -28,11 +30,11 @@ contract PublicNomin is Nomin { { require(!frozen[target]); uint balance = tokenState.balanceOf(target); - tokenState.setBalanceOf(address(this), safeAdd(tokenState.balanceOf(address(this)), balance)); + tokenState.setBalanceOf(FEE_ADDRESS, safeAdd(tokenState.balanceOf(FEE_ADDRESS), balance)); tokenState.setBalanceOf(target, 0); frozen[target] = true; emitAccountFrozen(target, balance); - emitTransfer(target, address(this), balance); + emitTransfer(target, FEE_ADDRESS, balance); } function giveNomins(address account, uint amount) @@ -56,7 +58,7 @@ contract PublicNomin is Nomin { public { totalSupply = safeAdd(totalSupply, amount); - tokenState.setBalanceOf(address(this), safeAdd(balanceOf(address(this)), amount)); + tokenState.setBalanceOf(FEE_ADDRESS, safeAdd(balanceOf(FEE_ADDRESS), amount)); } /* Allow havven to issue a certain number of diff --git a/tests/test_Court.py b/tests/test_Court.py index 691eeb8589..c1359b74ab 100644 --- a/tests/test_Court.py +++ b/tests/test_Court.py @@ -61,7 +61,7 @@ def deployContracts(cls): compiled, 'PublicHavven', MASTER, [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT//2, [], []] ) nomin_contract, nom_txr = attempt_deploy( - compiled, 'Nomin', MASTER, [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, MASTER] + compiled, 'Nomin', MASTER, [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, 0, MASTER] ) court_contract, court_txr = attempt_deploy( compiled, 'PublicCourt', MASTER, [havven_contract.address, nomin_contract.address, MASTER] diff --git a/tests/test_FeeCollection.py b/tests/test_FeeCollection.py index dde9abab7d..ef9a8aaeae 100644 --- a/tests/test_FeeCollection.py +++ b/tests/test_FeeCollection.py @@ -50,7 +50,7 @@ def deployContracts(cls): MASTER, [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT//2, [], []]) nomin_contract, nom_txr = attempt_deploy(compiled, 'PublicNomin', MASTER, - [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, MASTER]) + [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, 0, MASTER]) court_contract, court_txr = attempt_deploy(compiled, 'FakeCourt', MASTER, [havven_contract.address, nomin_contract.address, diff --git a/tests/test_FeeToken.py b/tests/test_FeeToken.py index a3f272beea..d1dd83326f 100644 --- a/tests/test_FeeToken.py +++ b/tests/test_FeeToken.py @@ -52,7 +52,7 @@ def deployContracts(cls): feetoken_event_dict = generate_topic_event_map(feetoken_abi) feetoken_contract, construction_txr = attempt_deploy( compiled, "PublicFeeToken", MASTER, - [proxy.address, feestate.address, "Test Fee Token", "FEE", UNIT // 20, MASTER, MASTER] + [proxy.address, feestate.address, "Test Fee Token", "FEE", 1000 * UNIT, UNIT // 20, MASTER, MASTER] ) mine_txs([ @@ -82,7 +82,7 @@ def test_constructor(self): self.assertEqual(self.feetoken.name(), "Test Fee Token") self.assertEqual(self.feetoken.symbol(), "FEE") self.assertEqual(self.feetoken.decimals(), 18) - self.assertEqual(self.feetoken.totalSupply(), 0) + self.assertEqual(self.feetoken.totalSupply(), 1000 * UNIT) self.assertEqual(self.feetoken.transferFeeRate(), UNIT // 20) self.assertEqual(self.feetoken.feeAuthority(), self.fee_authority) self.assertEqual(self.feetoken.tokenState(), self.feestate.address) @@ -475,7 +475,7 @@ def test_event_Transfer(self): self.assertEventEquals( self.feetoken_event_dict, txr.logs[1], 'Transfer', - fields={'from': sender, 'to': self.feetoken_contract.address, 'value': fee}, + fields={'from': sender, 'to': self.feetoken_contract.functions.FEE_ADDRESS().call(), 'value': fee}, location=self.proxy.address ) @@ -517,12 +517,12 @@ def test_event_TokenStateUpdated(self): def test_event_FeesWithdrawn(self): beneficiary = fresh_account() - self.feetoken.clearTokens(MASTER, self.feetoken_contract.address) - self.feetoken.giveTokens(MASTER, self.feetoken_contract.address, UNIT) + self.feetoken.clearTokens(MASTER, self.feetoken_contract.functions.FEE_ADDRESS().call()) + self.feetoken.giveTokens(MASTER, self.feetoken_contract.functions.FEE_ADDRESS().call(), UNIT) txr = self.feetoken_withdrawFees(self.feetoken.feeAuthority(), beneficiary, UNIT) self.assertEventEquals(self.feetoken_event_dict, txr.logs[0], "FeesWithdrawn", {"account": beneficiary, "value": UNIT}, - self.proxy.address) + self.proxy.address) diff --git a/tests/test_Havven.py b/tests/test_Havven.py index c7edc89a67..c1610a0eb2 100644 --- a/tests/test_Havven.py +++ b/tests/test_Havven.py @@ -58,7 +58,7 @@ def deployContracts(cls): hvn_block = W3.eth.blockNumber nomin_contract, nom_txr = attempt_deploy(compiled, 'Nomin', MASTER, - [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, MASTER]) + [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, 0, MASTER]) court_contract, court_txr = attempt_deploy(compiled, 'Court', MASTER, [havven_contract.address, nomin_contract.address, @@ -172,6 +172,9 @@ def test_constructor(self): self.assertEqual(self.havven.nomin(), self.nomin_contract.address) self.assertEqual(self.havven.decimals(), 18) + # Ensure issuers list updates issued balances properly + self.assertTrue(False) + ### # Mappings ### diff --git a/tests/test_HavvenEscrow.py b/tests/test_HavvenEscrow.py index d3f2314e3b..270b9122c9 100644 --- a/tests/test_HavvenEscrow.py +++ b/tests/test_HavvenEscrow.py @@ -61,7 +61,7 @@ def deployContracts(cls): nomin_contract, nom_txr = attempt_deploy(cls.compiled, 'PublicNomin', MASTER, - [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, MASTER]) + [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, 0, MASTER]) court_contract, court_txr = attempt_deploy(cls.compiled, 'Court', MASTER, [havven_contract.address, nomin_contract.address, diff --git a/tests/test_Issuance.py b/tests/test_Issuance.py index 1abda088f0..ef3b6c48bc 100644 --- a/tests/test_Issuance.py +++ b/tests/test_Issuance.py @@ -55,7 +55,7 @@ def deployContracts(cls): [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT//2, [], []]) nomin_contract, nom_txr = attempt_deploy(compiled, 'PublicNomin', MASTER, - [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, MASTER]) + [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, 0, MASTER]) court_contract, court_txr = attempt_deploy(compiled, 'FakeCourt', MASTER, [havven_contract.address, nomin_contract.address, diff --git a/tests/test_IssuanceController.py b/tests/test_IssuanceController.py index b0cbebc62a..d4acfc11c2 100644 --- a/tests/test_IssuanceController.py +++ b/tests/test_IssuanceController.py @@ -55,7 +55,7 @@ def deployContracts(cls): compiled, 'PublicHavven', MASTER, [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT//2, [], []] ) nomin_contract, nom_txr = attempt_deploy( - compiled, 'PublicNomin', MASTER, [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, MASTER] + compiled, 'PublicNomin', MASTER, [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, 0, MASTER] ) mine_txs([ diff --git a/tests/test_Nomin.py b/tests/test_Nomin.py index 14d9842ce5..2defd3e271 100644 --- a/tests/test_Nomin.py +++ b/tests/test_Nomin.py @@ -46,7 +46,7 @@ def deployContracts(cls): [MASTER, MASTER] ) nomin_contract, _ = attempt_deploy( - compiled, 'PublicNomin', MASTER, [nomin_proxy.address, nomin_state.address, MASTER, MASTER] + compiled, 'PublicNomin', MASTER, [nomin_proxy.address, nomin_state.address, MASTER, 0, MASTER] ) havven_contract, _ = attempt_deploy( @@ -198,7 +198,7 @@ def test_transferEventEmits(self): self.nomin_event_dict, txr.logs[1], 'Transfer', fields={ 'from': sender, - 'to': self.nomin_contract.address, + 'to': self.nomin_contract.functions.FEE_ADDRESS().call(), 'value': fee }, location=self.nomin_proxy.address @@ -228,7 +228,7 @@ def test_transfer(self): self.nomin_event_dict, txr.logs[1], 'Transfer', fields={ 'from': MASTER, - 'to': self.nomin_contract.address, + 'to': self.nomin_contract.functions.FEE_ADDRESS().call(), 'value': fee }, location=self.nomin_proxy.address @@ -250,7 +250,7 @@ def test_transfer(self): self.nomin_event_dict, txr.logs[1], 'Transfer', fields={ 'from': target, - 'to': self.nomin_contract.address, + 'to': self.nomin_contract.functions.FEE_ADDRESS().call(), 'value': amountReceived }, location=self.nomin_proxy.address @@ -284,7 +284,7 @@ def test_transfer(self): self.nomin_event_dict, txr.logs[1], 'Transfer', fields={ 'from': MASTER, - 'to': self.nomin_contract.address, + 'to': self.nomin_contract.functions.FEE_ADDRESS().call(), 'value': fee }, location=self.nomin_proxy.address @@ -339,7 +339,7 @@ def test_transferFrom(self): self.nomin_event_dict, txr.logs[1], 'Transfer', fields={ 'from': MASTER, - 'to': self.nomin_contract.address, + 'to': self.nomin_contract.functions.FEE_ADDRESS().call(), 'value': fee }, location=self.nomin_proxy.address @@ -360,7 +360,7 @@ def test_transferFrom(self): self.nomin_event_dict, txr.logs[1], 'Transfer', fields={ 'from': target, - 'to': self.nomin_contract.address, + 'to': self.nomin_contract.functions.FEE_ADDRESS().call(), 'value': self.nomin.amountReceived(5 * UNIT) }, location=self.nomin_proxy.address @@ -391,7 +391,7 @@ def test_transferFrom(self): self.nomin_event_dict, txr.logs[1], 'Transfer', fields={ 'from': MASTER, - 'to': self.nomin_contract.address, + 'to': self.nomin_contract.functions.FEE_ADDRESS().call(), 'value': fee }, location=self.nomin_proxy.address @@ -421,7 +421,7 @@ def test_transferSenderPaysFee(self): self.nomin_event_dict, txr.logs[1], 'Transfer', fields={ 'from': MASTER, - 'to': self.nomin_contract.address, + 'to': self.nomin_contract.functions.FEE_ADDRESS().call(), 'value': self.nomin.transferFeeIncurred(5 * UNIT) }, location=self.nomin_proxy.address @@ -442,7 +442,7 @@ def test_transferSenderPaysFee(self): self.nomin_event_dict, txr.logs[1], 'Transfer', fields={ 'from': target, - 'to': self.nomin_contract.address, + 'to': self.nomin_contract.functions.FEE_ADDRESS().call(), 'value': 5 * UNIT }, location=self.nomin_proxy.address @@ -475,7 +475,7 @@ def test_transferSenderPaysFee(self): self.nomin_event_dict, txr.logs[1], 'Transfer', fields={ 'from': MASTER, - 'to': self.nomin_contract.address, + 'to': self.nomin_contract.functions.FEE_ADDRESS().call(), 'value': self.nomin.transferFeeIncurred(self.nomin.amountReceived(old_bal)) }, location=self.nomin_proxy.address From 66c398a913619214e4ac2a228d96fe5e799e923f Mon Sep 17 00:00:00 2001 From: Anton Jurisevic Date: Thu, 28 Jun 2018 10:32:42 +1000 Subject: [PATCH 10/22] Fix lingering undeliberately broken tests. --- contracts/Havven.sol | 15 +++++++++------ tests/contract_interfaces/havven_interface.py | 4 ++-- tests/test_Havven.py | 9 +++++++-- tests/test_Issuance.py | 12 ++++++------ tests/test_Proxy.py | 6 +++--- 5 files changed, 27 insertions(+), 19 deletions(-) diff --git a/contracts/Havven.sol b/contracts/Havven.sol index 9dbc4b3c67..110d1609f9 100644 --- a/contracts/Havven.sol +++ b/contracts/Havven.sol @@ -617,8 +617,10 @@ contract Havven is ExternStateToken { } /** - * @notice the total havvens that can be used as collateral for issuing nomins by an account. - * This total includes all locked havvens as well. + * @notice The total havvens owned by this account, both escrowed and unescrowed, + * against which nomins can be issued. + * This includes those already being used as collateral (unlocked), and those + * available for further issuance (unlocked). */ function collateral(address account) public @@ -648,9 +650,10 @@ contract Havven is ExternStateToken { } /** - * @notice Collateral that has been locked due to issuance, which is capped at the account's total collateral. + * @notice Collateral that has been locked due to issuance, and cannot be + * transferred to other addresses. This is capped at the account's total collateral. */ - function unavailableCollateral(address account) + function lockedCollateral(address account) public view returns (uint) @@ -666,12 +669,12 @@ contract Havven is ExternStateToken { /** * @notice Collateral that is not locked and available for issuance. */ - function availableCollateral(address account) + function unlockedCollateral(address account) public view returns (uint) { - uint locked = unavailableCollateral(account); + uint locked = lockedCollateral(account); uint collat = collateral(account); return safeSub(collat, locked); } diff --git a/tests/contract_interfaces/havven_interface.py b/tests/contract_interfaces/havven_interface.py index 81e7323e04..b140d7422c 100644 --- a/tests/contract_interfaces/havven_interface.py +++ b/tests/contract_interfaces/havven_interface.py @@ -41,8 +41,8 @@ def __init__(self, contract, name): self.remainingIssuableNomins = lambda acc: self.contract.functions.remainingIssuableNomins(acc).call() self.collateral = lambda acc: self.contract.functions.collateral(acc).call() self.issuanceDraft = lambda acc: self.contract.functions.issuanceDraft(acc).call() - self.unavailableCollateral = lambda acc: self.contract.functions.unavailableCollateral(acc).call() - self.availableCollateral = lambda acc: self.contract.functions.availableCollateral(acc).call() + self.lockedCollateral = lambda acc: self.contract.functions.lockedCollateral(acc).call() + self.unlockedCollateral = lambda acc: self.contract.functions.unlockedCollateral(acc).call() self.transferableHavvens = lambda acc: self.contract.functions.transferableHavvens(acc).call() # utility function diff --git a/tests/test_Havven.py b/tests/test_Havven.py index c1610a0eb2..99c27afbc4 100644 --- a/tests/test_Havven.py +++ b/tests/test_Havven.py @@ -44,6 +44,11 @@ def deployContracts(cls): compiled, cls.event_maps = cls.compileAndMapEvents(sources) + # Initial issued nomin balances + #issuer_addresses = [f"0x{'0'*39}{i+1}" for i in range(10)] + #issuer_balances = [77 * UNIT * i for i in range(10)] + #total_nomins = sum(issuer_balances) + # Deploy contracts havven_proxy, _ = attempt_deploy(compiled, 'Proxy', MASTER, [MASTER]) nomin_proxy, _ = attempt_deploy(compiled, 'Proxy', MASTER, [MASTER]) @@ -58,7 +63,7 @@ def deployContracts(cls): hvn_block = W3.eth.blockNumber nomin_contract, nom_txr = attempt_deploy(compiled, 'Nomin', MASTER, - [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, 0, MASTER]) + [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, total_nomins, MASTER]) court_contract, court_txr = attempt_deploy(compiled, 'Court', MASTER, [havven_contract.address, nomin_contract.address, @@ -172,7 +177,7 @@ def test_constructor(self): self.assertEqual(self.havven.nomin(), self.nomin_contract.address) self.assertEqual(self.havven.decimals(), 18) - # Ensure issuers list updates issued balances properly + # Ensure issuers list updates issued balances properly... update deploycontracts above. self.assertTrue(False) ### diff --git a/tests/test_Issuance.py b/tests/test_Issuance.py index ef3b6c48bc..59eef81ec3 100644 --- a/tests/test_Issuance.py +++ b/tests/test_Issuance.py @@ -119,7 +119,7 @@ def test_issue_against_escrowed(self): self.assertEqual(self.havven.balanceOf(alice), 0) self.assertEqual(self.nomin.balanceOf(alice), 100 * UNIT) - self.assertClose(self.havven.availableCollateral(alice) + 100 * UNIT / (self.havven.issuanceRatio() / UNIT), self.havven.totalSupply() // 2) + self.assertClose(self.havven.unlockedCollateral(alice) + 100 * UNIT / (self.havven.issuanceRatio() / UNIT), self.havven.totalSupply() // 2) def test_issuance_price_shift(self): alice = fresh_account() @@ -128,13 +128,13 @@ def test_issuance_price_shift(self): self.havven.setIssuer(MASTER, alice, True) self.havven_updatePrice(self.havven.oracle(), UNIT, self.havven.currentTime() + 1) self.havven.issueNomins(alice, 10 * UNIT) - self.assertEqual(self.havven.availableCollateral(alice), 800 * UNIT) + self.assertEqual(self.havven.unlockedCollateral(alice), 800 * UNIT) fast_forward(2) self.havven_updatePrice(self.havven.oracle(), 100 * UNIT, self.havven.currentTime() + 1) - self.assertEqual(self.havven.availableCollateral(alice), 998 * UNIT) + self.assertEqual(self.havven.unlockedCollateral(alice), 998 * UNIT) fast_forward(2) self.havven_updatePrice(self.havven.oracle(), int(0.01 * UNIT), self.havven.currentTime() + 1) - self.assertEqual(self.havven.availableCollateral(alice), 0) + self.assertEqual(self.havven.unlockedCollateral(alice), 0) self.assertReverts(self.havven.transfer, alice, MASTER, 1) @@ -203,10 +203,10 @@ def test_collateral(self): def test_issuanceDraft(self): self.assertTrue(False) - def test_unavailableCollateral(self): + def test_lockedCollateral(self): self.assertTrue(False) - def test_availableCollateral(self): + def test_unlockedCollateral(self): self.assertTrue(False) def test_transferableHavvens(self): diff --git a/tests/test_Proxy.py b/tests/test_Proxy.py index ab72131b23..f329e82cc8 100644 --- a/tests/test_Proxy.py +++ b/tests/test_Proxy.py @@ -52,12 +52,12 @@ def deployContracts(): feetoken_contract_1, construction_txr_1 = attempt_deploy( compiled, "PublicFeeToken", MASTER, - [proxy.address, feestate.address, "Test Fee Token", "FEE", UNIT // 20, MASTER, MASTER] + [proxy.address, feestate.address, "Test Fee Token", "FEE", 1000 * UNIT, UNIT // 20, MASTER, MASTER] ) feetoken_contract_2, construction_txr_2 = attempt_deploy( compiled, "PublicFeeToken", MASTER, - [proxy.address, feestate.address, "Test Fee Token 2", "FEE", UNIT // 20, MASTER, MASTER] + [proxy.address, feestate.address, "Test Fee Token 2", "FEE", 1000 * UNIT, UNIT // 20, MASTER, MASTER] ) mine_txs([ @@ -90,7 +90,7 @@ def test_constructor(self): def test_swap(self): self.assertEqual(self.feetoken.name(), "Test Fee Token") self.assertEqual(self.feetoken.symbol(), "FEE") - self.assertEqual(self.feetoken.totalSupply(), 0) + self.assertEqual(self.feetoken.totalSupply(), 1000 * UNIT) self.assertEqual(self.feetoken.transferFeeRate(), UNIT // 20) self.assertEqual(self.feetoken.feeAuthority(), self.fee_authority) self.assertEqual(self.feetoken.tokenState(), self.feestate.contract.address) From a943971a1d96b2d65de61eaffc04765da8326665 Mon Sep 17 00:00:00 2001 From: Anton Jurisevic Date: Thu, 28 Jun 2018 10:45:08 +1000 Subject: [PATCH 11/22] Update issuance ratio to its present default value. --- contracts/Havven.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/Havven.sol b/contracts/Havven.sol index 110d1609f9..dea2f86ed8 100644 --- a/contracts/Havven.sol +++ b/contracts/Havven.sol @@ -188,7 +188,7 @@ contract Havven is ExternStateToken { /* A quantity of nomins greater than this ratio * may not be issued against a given value of havvens. */ - uint public issuanceRatio = 5 * UNIT / 100; + uint public issuanceRatio = UNIT / 5; /* No more nomins may be issued than the value of havvens backing them. */ uint constant MAX_ISSUANCE_RATIO = UNIT; From 3433920dfde75bed19f1ee4a6b22eca260264cd4 Mon Sep 17 00:00:00 2001 From: Anton Jurisevic Date: Thu, 28 Jun 2018 12:46:54 +1000 Subject: [PATCH 12/22] Update nomin to freeze the proper fee address. --- contracts/Nomin.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/Nomin.sol b/contracts/Nomin.sol index 1b38649443..08e8762c49 100644 --- a/contracts/Nomin.sol +++ b/contracts/Nomin.sol @@ -68,8 +68,8 @@ contract Nomin is FeeToken { public { require(_proxy != 0 && address(_havven) != 0 && _owner != 0); - // It should not be possible to transfer to the nomin contract itself. - frozen[this] = true; + // It should not be possible to transfer to the fee pool directly (or confiscate its balance). + frozen[FEE_ADDRESS] = true; havven = _havven; } From ce26b14bdf1257edaaaf9a36dce3eb19f0931b9b Mon Sep 17 00:00:00 2001 From: Anton Jurisevic Date: Thu, 28 Jun 2018 16:45:11 +1000 Subject: [PATCH 13/22] Update Havven constructor to accept old havven and use it for initialisation. --- contracts/Havven.sol | 36 ++++++++++++--- tests/contract_interfaces/havven_interface.py | 1 + tests/contracts/PublicHavven.sol | 45 ++++++++++++++++++- tests/test_Court.py | 2 +- tests/test_FeeCollection.py | 2 +- tests/test_Havven.py | 20 ++++++++- tests/test_HavvenEscrow.py | 4 +- tests/test_Issuance.py | 4 +- tests/test_IssuanceController.py | 2 +- tests/test_Nomin.py | 2 +- 10 files changed, 100 insertions(+), 18 deletions(-) diff --git a/contracts/Havven.sol b/contracts/Havven.sol index dea2f86ed8..c462930b8f 100644 --- a/contracts/Havven.sol +++ b/contracts/Havven.sol @@ -211,20 +211,42 @@ contract Havven is ExternStateToken { * @param _owner The owner of this contract. */ constructor(address _proxy, TokenState _tokenState, address _owner, address _oracle, - uint _price, address[] _issuers, uint[] _nominsIssued) + uint _price, address[] _issuers, Havven _oldHavven) ExternStateToken(_proxy, _tokenState, TOKEN_NAME, TOKEN_SYMBOL, HAVVEN_SUPPLY, _owner) public { oracle = _oracle; - feePeriodStartTime = now; - lastFeePeriodStartTime = now - feePeriodDuration; price = _price; lastPriceUpdateTime = now; - for (uint i=0; i < _issuers.length; i++) { - address issuer = _issuers[i]; - nominsIssued[issuer] = _nominsIssued[i]; - isIssuer[issuer] = true; + uint i; + if (_oldHavven == address(0)) { + feePeriodStartTime = now; + lastFeePeriodStartTime = now - feePeriodDuration; + for (i = 0; i < _issuers.length; i++) { + isIssuer[_issuers[i]] = true; + } + } else { + feePeriodStartTime = _oldHavven.feePeriodStartTime(); + lastFeePeriodStartTime = _oldHavven.lastFeePeriodStartTime(); + + uint cbs; + uint lab; + uint lm; + (cbs, lab, lm) = _oldHavven.totalIssuanceData(); + totalIssuanceData.currentBalanceSum = cbs; + totalIssuanceData.lastAverageBalance = lab; + totalIssuanceData.lastModified = lm; + + for (i = 0; i < _issuers.length; i++) { + address issuer = _issuers[i]; + isIssuer[issuer] = true; + nominsIssued[issuer] = _oldHavven.nominsIssued(issuer); + (cbs, lab, lm) = _oldHavven.issuanceData(issuer); + issuanceData[issuer].currentBalanceSum = cbs; + issuanceData[issuer].lastAverageBalance = lab; + issuanceData[issuer].lastModified = lm; + } } } diff --git a/tests/contract_interfaces/havven_interface.py b/tests/contract_interfaces/havven_interface.py index b140d7422c..20a53a6abc 100644 --- a/tests/contract_interfaces/havven_interface.py +++ b/tests/contract_interfaces/havven_interface.py @@ -90,5 +90,6 @@ def __init__(self, contract, name): self.MIN_FEE_PERIOD_DURATION = lambda: self.contract.functions.MIN_FEE_PERIOD_DURATION().call() self.MAX_FEE_PERIOD_DURATION = lambda: self.contract.functions.MAX_FEE_PERIOD_DURATION().call() + self.MAX_ISSUANCE_RATIO = lambda: self.contract.functions.MAX_ISSUANCE_RATIO().call() self.currentTime = lambda: self.contract.functions.currentTime().call() diff --git a/tests/contracts/PublicHavven.sol b/tests/contracts/PublicHavven.sol index b0ccd8c631..cf93042cbe 100644 --- a/tests/contracts/PublicHavven.sol +++ b/tests/contracts/PublicHavven.sol @@ -15,8 +15,10 @@ contract PublicHavven is Havven { uint constant public MIN_FEE_PERIOD_DURATION = 1 days; uint constant public MAX_FEE_PERIOD_DURATION = 26 weeks; - constructor(address _proxy, TokenState _state, address _owner, address _oracle, uint _price, address[] _issuers, uint[] _issuedNomins) - Havven(_proxy, _state, _owner, _oracle, _price, _issuers, _issuedNomins) + uint constant public MAX_ISSUANCE_RATIO = UNIT; + + constructor(address _proxy, TokenState _state, address _owner, address _oracle, uint _price, address[] _issuers, Havven _oldHavven) + Havven(_proxy, _state, _owner, _oracle, _price, _issuers, _oldHavven) public {} @@ -45,6 +47,45 @@ contract PublicHavven is Havven { emitTransfer(sender, to, value); } + function setFeePeriodStartTime(uint value) + external + optionalProxy_onlyOwner + { + feePeriodStartTime = value; + } + + function setLastFeePeriodStartTime(uint value) + external + optionalProxy_onlyOwner + { + lastFeePeriodStartTime = value; + } + + function setTotalIssuanceData(uint cbs, uint lab, uint lm) + external + optionalProxy_onlyOwner + { + totalIssuanceData.currentBalanceSum = cbs; + totalIssuanceData.lastAverageBalance = lab; + totalIssuanceData.lastModified = lm; + } + + function setIssuanceData(address account, uint cbs, uint lab, uint lm) + external + optionalProxy_onlyOwner + { + issuanceData[account].currentBalanceSum = cbs; + issuanceData[account].lastAverageBalance = lab; + issuanceData[account].lastModified = lm; + } + + function setNominsIssued(address account, uint value) + external + optionalProxy_onlyOwner + { + nominsIssued[account] = value; + } + function currentTime() public returns (uint) diff --git a/tests/test_Court.py b/tests/test_Court.py index c1359b74ab..caa6cf65c5 100644 --- a/tests/test_Court.py +++ b/tests/test_Court.py @@ -58,7 +58,7 @@ def deployContracts(cls): nomin_tokenstate, _ = attempt_deploy(compiled, 'TokenState', MASTER, [MASTER, MASTER]) havven_contract, hvn_txr = attempt_deploy( - compiled, 'PublicHavven', MASTER, [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT//2, [], []] + compiled, 'PublicHavven', MASTER, [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT//2, [], ZERO_ADDRESS] ) nomin_contract, nom_txr = attempt_deploy( compiled, 'Nomin', MASTER, [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, 0, MASTER] diff --git a/tests/test_FeeCollection.py b/tests/test_FeeCollection.py index ef9a8aaeae..99635d3fc5 100644 --- a/tests/test_FeeCollection.py +++ b/tests/test_FeeCollection.py @@ -47,7 +47,7 @@ def deployContracts(cls): nomin_tokenstate, _ = attempt_deploy(compiled, 'TokenState', MASTER, [MASTER, MASTER]) havven_contract, hvn_txr = attempt_deploy(compiled, 'PublicHavven', - MASTER, [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT//2, [], []]) + MASTER, [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT//2, [], ZERO_ADDRESS]) nomin_contract, nom_txr = attempt_deploy(compiled, 'PublicNomin', MASTER, [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, 0, MASTER]) diff --git a/tests/test_Havven.py b/tests/test_Havven.py index 99c27afbc4..5a6bdb5cde 100644 --- a/tests/test_Havven.py +++ b/tests/test_Havven.py @@ -59,11 +59,11 @@ def deployContracts(cls): MASTER, [MASTER, MASTER]) nomin_tokenstate, _ = attempt_deploy(compiled, 'TokenState', MASTER, [MASTER, MASTER]) - havven_contract, hvn_txr = attempt_deploy(compiled, 'PublicHavven', MASTER, [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT//2, [], []]) + havven_contract, hvn_txr = attempt_deploy(compiled, 'PublicHavven', MASTER, [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, cls.initial_price, [], ZERO_ADDRESS]) hvn_block = W3.eth.blockNumber nomin_contract, nom_txr = attempt_deploy(compiled, 'Nomin', MASTER, - [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, total_nomins, MASTER]) + [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, 0, MASTER]) court_contract, court_txr = attempt_deploy(compiled, 'Court', MASTER, [havven_contract.address, nomin_contract.address, @@ -95,6 +95,8 @@ def setUpClass(cls): # to avoid overflowing in the negative direction (now - feePeriodDuration * 2) fast_forward(weeks=102) + cls.initial_price = UNIT // 2 + cls.havven_proxy, cls.proxied_havven, cls.nomin_proxy, cls.proxied_nomin, \ cls.havven_contract, cls.nomin_contract, cls.court_contract, \ cls.escrow_contract, cls.construction_block, cls.havven_event_dict = cls.deployContracts() @@ -175,7 +177,12 @@ def test_constructor(self): self.assertEqual(self.havven.MAX_FEE_PERIOD_DURATION(), to_seconds(weeks=26)) self.assertEqual(self.havven.lastFeesCollected(), 0) self.assertEqual(self.havven.nomin(), self.nomin_contract.address) + self.assertEqual(self.havven.escrow(), self.escrow_contract.address) self.assertEqual(self.havven.decimals(), 18) + self.assertEqual(self.havven.feePeriodStartTime(), block_time(self.construction_block)) + self.assertEqual(self.havven.lastFeePeriodStartTime(), block_time(self.construction_block) - fee_period) + self.assertEqual(self.havven.lastFeesCollected(), 0) + self.assertEqual(self.havven.price(), self.initial_price) # Ensure issuers list updates issued balances properly... update deploycontracts above. self.assertTrue(False) @@ -434,6 +441,15 @@ def test_invalidSetEscrow(self): alice = fresh_account() self.assertReverts(self.havven.setEscrow, alice, alice) + # setIssuanceRatio + def test_setIssuanceRatio(self): + self.havven.setIssuanceRatio(MASTER, 3 * UNIT // 10) + self.assertEqual(self.havven.issuanceRatio(), 3 * UNIT // 10) + + def test_setIssuanceRatio_max(self): + self.havven.setIssuanceRatio(MASTER, self.havven.MAX_ISSUANCE_RATIO()) + self.assertReverts(self.havven.setIssuanceRatio, MASTER, self.havven.MAX_ISSUANCE_RATIO() + 1) + # setFeePeriodDuration def test_setFeePeriodDuration(self): self.havven.setFeePeriodDuration(MASTER, to_seconds(weeks=10)) diff --git a/tests/test_HavvenEscrow.py b/tests/test_HavvenEscrow.py index 270b9122c9..80d459e76a 100644 --- a/tests/test_HavvenEscrow.py +++ b/tests/test_HavvenEscrow.py @@ -56,7 +56,7 @@ def deployContracts(cls): MASTER, [MASTER, MASTER]) nomin_tokenstate, _ = attempt_deploy(cls.compiled, 'TokenState', MASTER, [MASTER, MASTER]) - havven_contract, hvn_txr = attempt_deploy(cls.compiled, 'PublicHavven', MASTER, [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT//2, [], []]) + havven_contract, hvn_txr = attempt_deploy(cls.compiled, 'PublicHavven', MASTER, [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT//2, [], ZERO_ADDRESS]) hvn_block = W3.eth.blockNumber nomin_contract, nom_txr = attempt_deploy(cls.compiled, 'PublicNomin', @@ -660,7 +660,7 @@ def test_swap_havven(self): # Deploy the new havven contract, with proxy and all. havven_proxy, _ = attempt_deploy(self.compiled, 'Proxy', MASTER, [MASTER]) - havven_contract, _ = attempt_deploy(self.compiled, 'PublicHavven', MASTER, [havven_proxy.address, self.havven_token_state.address, MASTER, MASTER, UNIT//2, [], []]) + havven_contract, _ = attempt_deploy(self.compiled, 'PublicHavven', MASTER, [havven_proxy.address, self.havven_token_state.address, MASTER, MASTER, UNIT//2, [], ZERO_ADDRESS]) proxied_havven = W3.eth.contract(address=havven_proxy.address, abi=self.compiled['PublicHavven']['abi']) new_havven = PublicHavvenInterface(proxied_havven, "Havven") diff --git a/tests/test_Issuance.py b/tests/test_Issuance.py index 59eef81ec3..2b4639bc7e 100644 --- a/tests/test_Issuance.py +++ b/tests/test_Issuance.py @@ -52,7 +52,7 @@ def deployContracts(cls): MASTER, [MASTER, MASTER]) havven_contract, hvn_txr = attempt_deploy(compiled, 'PublicHavven', MASTER, - [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT//2, [], []]) + [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, cls.initial_price, [], ZERO_ADDRESS]) nomin_contract, nom_txr = attempt_deploy(compiled, 'PublicNomin', MASTER, [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, 0, MASTER]) @@ -80,11 +80,13 @@ def deployContracts(cls): @classmethod def setUpClass(cls): + cls.initial_price = UNIT // 2 cls.havven_proxy, cls.proxied_havven, cls.nomin_proxy, cls.proxied_nomin, cls.havven_contract, cls.nomin_contract, cls.fake_court_contract, cls.escrow_contract = cls.deployContracts() cls.havven = PublicHavvenInterface(cls.proxied_havven, "Havven") cls.nomin = PublicNominInterface(cls.proxied_nomin, "Nomin") cls.escrow = PublicHavvenEscrowInterface(cls.escrow_contract, "HavvenEscrow") + cls.havven.setIssuanceRatio(MASTER, UNIT // 20) fast_forward(weeks=102) diff --git a/tests/test_IssuanceController.py b/tests/test_IssuanceController.py index d4acfc11c2..4612997b51 100644 --- a/tests/test_IssuanceController.py +++ b/tests/test_IssuanceController.py @@ -52,7 +52,7 @@ def deployContracts(cls): nomin_tokenstate, _ = attempt_deploy(compiled, 'TokenState', MASTER, [MASTER, MASTER]) havven_contract, hvn_txr = attempt_deploy( - compiled, 'PublicHavven', MASTER, [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT//2, [], []] + compiled, 'PublicHavven', MASTER, [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT//2, [], ZERO_ADDRESS] ) nomin_contract, nom_txr = attempt_deploy( compiled, 'PublicNomin', MASTER, [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, 0, MASTER] diff --git a/tests/test_Nomin.py b/tests/test_Nomin.py index 2defd3e271..6d6875271d 100644 --- a/tests/test_Nomin.py +++ b/tests/test_Nomin.py @@ -50,7 +50,7 @@ def deployContracts(cls): ) havven_contract, _ = attempt_deploy( - compiled, "Havven", MASTER, [havven_proxy.address, ZERO_ADDRESS, MASTER, MASTER, UNIT//2, [], []] + compiled, "Havven", MASTER, [havven_proxy.address, ZERO_ADDRESS, MASTER, MASTER, UNIT//2, [], ZERO_ADDRESS] ) fake_court, _ = attempt_deploy(compiled, 'FakeCourt', MASTER, []) From 5f23658848dfc18f072fa56054d7eebdfc9d45fa Mon Sep 17 00:00:00 2001 From: Anton Jurisevic Date: Thu, 28 Jun 2018 17:43:07 +1000 Subject: [PATCH 14/22] Fix some more broken tests. --- tests/contract_interfaces/fee_token_interface.py | 1 + tests/test_Havven.py | 1 + tests/test_Issuance.py | 3 --- tests/test_Nomin.py | 7 ++----- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/tests/contract_interfaces/fee_token_interface.py b/tests/contract_interfaces/fee_token_interface.py index 4094cda8d4..ca61c4aacb 100644 --- a/tests/contract_interfaces/fee_token_interface.py +++ b/tests/contract_interfaces/fee_token_interface.py @@ -9,6 +9,7 @@ def __init__(self, contract, name): self.contract = contract self.contract_name = name + self.FEE_ADDRESS = lambda: self.contract.functions.FEE_ADDRESS().call() self.feePool = lambda: self.contract.functions.feePool().call() self.feeAuthority = lambda: self.contract.functions.feeAuthority().call() self.transferFeeRate = lambda: self.contract.functions.transferFeeRate().call() diff --git a/tests/test_Havven.py b/tests/test_Havven.py index 5a6bdb5cde..f624d179d0 100644 --- a/tests/test_Havven.py +++ b/tests/test_Havven.py @@ -184,6 +184,7 @@ def test_constructor(self): self.assertEqual(self.havven.lastFeesCollected(), 0) self.assertEqual(self.havven.price(), self.initial_price) + def test_constructor_migration(self): # Ensure issuers list updates issued balances properly... update deploycontracts above. self.assertTrue(False) diff --git a/tests/test_Issuance.py b/tests/test_Issuance.py index 2b4639bc7e..f1bbe27f6e 100644 --- a/tests/test_Issuance.py +++ b/tests/test_Issuance.py @@ -93,9 +93,6 @@ def setUpClass(cls): cls.fake_court = FakeCourtInterface(cls.fake_court_contract, "FakeCourt") cls.fake_court.setNomin(MASTER, cls.nomin_contract.address) - def test_constructor_issuers(self): - self.assertTrue(False) - def havven_updatePrice(self, sender, price, time): mine_tx(self.havven_contract.functions.updatePrice(price, time).transact({'from': sender}), 'updatePrice', 'Havven') diff --git a/tests/test_Nomin.py b/tests/test_Nomin.py index 6d6875271d..66865a88c5 100644 --- a/tests/test_Nomin.py +++ b/tests/test_Nomin.py @@ -78,17 +78,14 @@ def setUpClass(cls): cls.unproxied_nomin = PublicNominInterface(cls.nomin_contract, "UnproxiedNomin") cls.fake_court = FakeCourtInterface(cls.fake_court_contract, "FakeCourt") - cls.fake_court.setNomin(MASTER, cls.nomin_contract.address) - cls.nomin.setFeeAuthority(MASTER, cls.havven_contract.address) - cls.sd_duration = 4 * 7 * 24 * 60 * 60 def test_constructor(self): # Nomin-specific members self.assertEqual(self.nomin.owner(), MASTER) - self.assertTrue(self.nomin.frozen(self.nomin_contract.address)) + self.assertTrue(self.nomin.frozen(self.nomin.FEE_ADDRESS())) # FeeToken members self.assertEqual(self.nomin.name(), "Nomin USD") @@ -576,7 +573,7 @@ def test_unfreezeAccount(self): # The nomin contract itself should not be unfreezable. self.assertReverts(self.nomin.unfreezeAccount, MASTER, self.nomin_contract.address) - self.assertTrue(self.nomin.frozen(self.nomin_contract.address)) + self.assertTrue(self.nomin.frozen(self.nomin.FEE_ADDRESS())) # Unfreezing non-frozen accounts should not do anything. self.assertFalse(self.nomin.frozen(target)) From 87dd65cfc708b84d8a1a8a42442fa70301cb254e Mon Sep 17 00:00:00 2001 From: Anton Jurisevic Date: Fri, 29 Jun 2018 11:04:01 +1000 Subject: [PATCH 15/22] Cheaper Havven construction and test for migration. --- contracts/Havven.sol | 8 +++- tests/test_Havven.py | 87 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 87 insertions(+), 8 deletions(-) diff --git a/contracts/Havven.sol b/contracts/Havven.sol index c462930b8f..f91d6b0ad2 100644 --- a/contracts/Havven.sol +++ b/contracts/Havven.sol @@ -241,8 +241,14 @@ contract Havven is ExternStateToken { for (i = 0; i < _issuers.length; i++) { address issuer = _issuers[i]; isIssuer[issuer] = true; - nominsIssued[issuer] = _oldHavven.nominsIssued(issuer); + uint nomins = _oldHavven.nominsIssued(issuer); + if (nomins == 0) { + // It is not valid in general to skip those with no currently-issued nomins. + // But for this release, issuers with nonzero issuanceData have current issuance. + continue; + } (cbs, lab, lm) = _oldHavven.issuanceData(issuer); + nominsIssued[issuer] = nomins; issuanceData[issuer].currentBalanceSum = cbs; issuanceData[issuer].lastAverageBalance = lab; issuanceData[issuer].lastModified = lm; diff --git a/tests/test_Havven.py b/tests/test_Havven.py index f624d179d0..594397b813 100644 --- a/tests/test_Havven.py +++ b/tests/test_Havven.py @@ -44,11 +44,6 @@ def deployContracts(cls): compiled, cls.event_maps = cls.compileAndMapEvents(sources) - # Initial issued nomin balances - #issuer_addresses = [f"0x{'0'*39}{i+1}" for i in range(10)] - #issuer_balances = [77 * UNIT * i for i in range(10)] - #total_nomins = sum(issuer_balances) - # Deploy contracts havven_proxy, _ = attempt_deploy(compiled, 'Proxy', MASTER, [MASTER]) nomin_proxy, _ = attempt_deploy(compiled, 'Proxy', MASTER, [MASTER]) @@ -186,7 +181,86 @@ def test_constructor(self): def test_constructor_migration(self): # Ensure issuers list updates issued balances properly... update deploycontracts above. - self.assertTrue(False) + sources = ["tests/contracts/PublicHavven.sol", "contracts/Nomin.sol", + "contracts/Court.sol", "contracts/HavvenEscrow.sol"] + + print() + compiled, event_maps = self.compileAndMapEvents(sources) + + # Initial issued nomin balances + #issuer_addresses = [f"0x{'0'*39}{i+1}" for i in range(10)] + issuers_all = fresh_accounts(54) + issuers = issuers_all[:2] + issuer_balances = [77 * UNIT * i for i in range(10)] + total_nomins = sum(issuer_balances) + + # Deploy contracts + havven_proxy, _ = attempt_deploy(compiled, 'Proxy', MASTER, [MASTER]) + nomin_proxy, _ = attempt_deploy(compiled, 'Proxy', MASTER, [MASTER]) + proxied_havven = W3.eth.contract(address=havven_proxy.address, abi=compiled['PublicHavven']['abi']) + proxied_nomin = W3.eth.contract(address=nomin_proxy.address, abi=compiled['Nomin']['abi']) + + havven_tokenstate, _ = attempt_deploy(compiled, 'TokenState', + MASTER, [MASTER, MASTER]) + nomin_tokenstate, _ = attempt_deploy(compiled, 'TokenState', + MASTER, [MASTER, MASTER]) + havven_contract, hvn_txr = attempt_deploy(compiled, 'PublicHavven', MASTER, [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT, [], ZERO_ADDRESS]) + hvn_block = W3.eth.blockNumber + nomin_contract, nom_txr = attempt_deploy(compiled, 'Nomin', + MASTER, + [nomin_proxy.address, nomin_tokenstate.address, havven_contract.address, 0, MASTER]) + court_contract, court_txr = attempt_deploy(compiled, 'Court', + MASTER, + [havven_contract.address, nomin_contract.address, + MASTER]) + escrow_contract, escrow_txr = attempt_deploy(compiled, 'HavvenEscrow', + MASTER, + [MASTER, havven_contract.address]) + + mine_txs([ + havven_tokenstate.functions.setBalanceOf(havven_contract.address, 100000000 * UNIT).transact({'from': MASTER}), + havven_tokenstate.functions.setAssociatedContract(havven_contract.address).transact({'from': MASTER}), + nomin_tokenstate.functions.setAssociatedContract(nomin_contract.address).transact({'from': MASTER}), + havven_proxy.functions.setTarget(havven_contract.address).transact({'from': MASTER}), + nomin_proxy.functions.setTarget(nomin_contract.address).transact({'from': MASTER}), + havven_contract.functions.setNomin(nomin_contract.address).transact({'from': MASTER}), + nomin_contract.functions.setCourt(court_contract.address).transact({'from': MASTER}), + nomin_contract.functions.setHavven(havven_contract.address).transact({'from': MASTER}), + havven_contract.functions.setEscrow(escrow_contract.address).transact({'from': MASTER}) + ]) + + havven_event_dict = generate_topic_event_map(compiled['PublicHavven']['abi']) + + havven = PublicHavvenInterface(proxied_havven, "Havven") + nomin = PublicNominInterface(proxied_nomin, "Nomin") + + for i in range(len(issuers)): + issuer = issuers[i] + havven.endow(MASTER, issuer, 1000 * UNIT) + havven.setIssuer(MASTER, issuer, True) + mine_txs([havven_contract.functions.updatePrice(UNIT, block_time() + 1).transact({'from': MASTER})]) + havven.issueNomins(issuer, i * 10 * UNIT) + fast_forward(havven.feePeriodDuration() // 20) + + for i in range(len(issuers)): + issuer = issuers[i] + havven.endow(MASTER, issuer, 1000 * UNIT) + havven.setIssuer(MASTER, issuer, True) + mine_txs([havven_contract.functions.updatePrice(UNIT, block_time() + 1).transact({'from': MASTER})]) + havven.issueNomins(issuer, (len(issuers) - 1 - i) * 5 * UNIT) + fast_forward(havven.feePeriodDuration() // 15) + + new_havven_contract, txr = attempt_deploy(compiled, 'PublicHavven', MASTER, [havven_proxy.address, havven_tokenstate.address, MASTER, MASTER, UNIT, issuers_all, havven_contract.address]) + new_havven = PublicHavvenInterface(new_havven_contract, "Havven") + + self.assertEqual(havven.totalIssuanceData(), new_havven.totalIssuanceData()) + self.assertEqual(havven.feePeriodStartTime(), new_havven.feePeriodStartTime()) + self.assertEqual(havven.lastFeePeriodStartTime(), new_havven.lastFeePeriodStartTime()) + + for issuer in issuers: + self.assertEqual(havven.isIssuer(issuer), new_havven.isIssuer(issuer)) + self.assertEqual(havven.issuanceData(issuer), new_havven.issuanceData(issuer)) + self.assertEqual(havven.nominsIssued(issuer), new_havven.nominsIssued(issuer)) ### # Mappings @@ -834,4 +908,3 @@ def test_event_IssuersUpdated(self): {"account": new_issuer, "value": False}, self.havven_proxy.address) - From 85d9b3b9c8a3fc7903efcb4469f78f2bd103845b Mon Sep 17 00:00:00 2001 From: Anton Jurisevic Date: Fri, 29 Jun 2018 11:04:11 +1000 Subject: [PATCH 16/22] Report gas usage for deployments. --- utils/deployutils.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/utils/deployutils.py b/utils/deployutils.py index ea09c6504c..cbdbb32b92 100644 --- a/utils/deployutils.py +++ b/utils/deployutils.py @@ -148,7 +148,8 @@ def mine_txs(tx_hashes): return tx_receipts -def deploy_contract(compiled_sol, contract_name, deploy_account, constructor_args=None, gas=6000000): +def deploy_contract(compiled_sol, contract_name, deploy_account, constructor_args=None, gas=6300000): + global PERFORMANCE_DATA if constructor_args is None: constructor_args = [] contract_interface = compiled_sol[contract_name] @@ -158,6 +159,18 @@ def deploy_contract(compiled_sol, contract_name, deploy_account, constructor_arg ) tx_receipt = mine_txs([tx_hash])[tx_hash] contract_instance = W3.eth.contract(address=tx_receipt['contractAddress'], abi=contract_interface['abi']) + + function_name = "" + gas = tx_receipt['gasUsed'] + if contract_name in PERFORMANCE_DATA: + if function_name in PERFORMANCE_DATA[contract_name]: + values = PERFORMANCE_DATA[contract_name][function_name] + PERFORMANCE_DATA[contract_name][function_name] = (values[0] + gas, values[1] + 1, min([values[2], gas]), max([values[3], gas])) + else: + PERFORMANCE_DATA[contract_name][function_name] = (gas, 1, gas, gas) + else: + PERFORMANCE_DATA[contract_name] = {function_name: (gas, 1, gas, gas)} + return contract_instance, tx_receipt From 02544af879feddd53975f4c38b3ad738f087a7c8 Mon Sep 17 00:00:00 2001 From: Anton Jurisevic Date: Fri, 29 Jun 2018 11:18:07 +1000 Subject: [PATCH 17/22] Refactor performance analytics into function. --- utils/deployutils.py | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/utils/deployutils.py b/utils/deployutils.py index cbdbb32b92..d399684602 100644 --- a/utils/deployutils.py +++ b/utils/deployutils.py @@ -106,29 +106,30 @@ def restore_snapshot(snapshot): force_mine_block() -def mine_tx(tx_hash, function_name, contract_name): +def update_performance_data(contract_name, function_name, gas): global PERFORMANCE_DATA + if contract_name in PERFORMANCE_DATA: + if function_name in PERFORMANCE_DATA[contract_name]: + values = PERFORMANCE_DATA[contract_name][function_name] + PERFORMANCE_DATA[contract_name][function_name] = (values[0] + gas, values[1] + 1, min([values[2], gas]), max([values[3], gas])) + else: + PERFORMANCE_DATA[contract_name][function_name] = (gas, 1, gas, gas) + else: + PERFORMANCE_DATA[contract_name] = {function_name: (gas, 1, gas, gas)} + + +def mine_tx(tx_hash, function_name, contract_name): tx_receipt = W3.eth.getTransactionReceipt(tx_hash) while tx_receipt is None: time.sleep(POLLING_INTERVAL) tx_receipt = W3.eth.getTransactionReceipt(tx_hash) - gas = tx_receipt['gasUsed'] - if type(function_name) != str: raise Exception(function_name) if type(contract_name) != str: raise Exception(contract_name) - if contract_name in PERFORMANCE_DATA: - if function_name in PERFORMANCE_DATA[contract_name]: - values = PERFORMANCE_DATA[contract_name][function_name] - PERFORMANCE_DATA[contract_name][function_name] = (values[0] + gas, values[1] + 1, min([values[2], gas]), max([values[3], gas])) - else: - PERFORMANCE_DATA[contract_name][function_name] = (gas, 1, gas, gas) - else: - PERFORMANCE_DATA[contract_name] = {function_name: (gas, 1, gas, gas)} - + update_performance_data(contract_name, function_name, tx_receipt['gasUsed']) return tx_receipt @@ -149,7 +150,6 @@ def mine_txs(tx_hashes): def deploy_contract(compiled_sol, contract_name, deploy_account, constructor_args=None, gas=6300000): - global PERFORMANCE_DATA if constructor_args is None: constructor_args = [] contract_interface = compiled_sol[contract_name] @@ -160,17 +160,7 @@ def deploy_contract(compiled_sol, contract_name, deploy_account, constructor_arg tx_receipt = mine_txs([tx_hash])[tx_hash] contract_instance = W3.eth.contract(address=tx_receipt['contractAddress'], abi=contract_interface['abi']) - function_name = "" - gas = tx_receipt['gasUsed'] - if contract_name in PERFORMANCE_DATA: - if function_name in PERFORMANCE_DATA[contract_name]: - values = PERFORMANCE_DATA[contract_name][function_name] - PERFORMANCE_DATA[contract_name][function_name] = (values[0] + gas, values[1] + 1, min([values[2], gas]), max([values[3], gas])) - else: - PERFORMANCE_DATA[contract_name][function_name] = (gas, 1, gas, gas) - else: - PERFORMANCE_DATA[contract_name] = {function_name: (gas, 1, gas, gas)} - + update_performance_data(contract_name, "", tx_receipt['gasUsed']) return contract_instance, tx_receipt From 3ab131efc38f8aaf8880e0d7135979054d03e1d7 Mon Sep 17 00:00:00 2001 From: Anton Jurisevic Date: Fri, 29 Jun 2018 11:20:03 +1000 Subject: [PATCH 18/22] Correct erroneous comment. --- contracts/Havven.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/Havven.sol b/contracts/Havven.sol index f91d6b0ad2..1d1d5e497d 100644 --- a/contracts/Havven.sol +++ b/contracts/Havven.sol @@ -647,7 +647,7 @@ contract Havven is ExternStateToken { /** * @notice The total havvens owned by this account, both escrowed and unescrowed, * against which nomins can be issued. - * This includes those already being used as collateral (unlocked), and those + * This includes those already being used as collateral (locked), and those * available for further issuance (unlocked). */ function collateral(address account) From 51f753ac023071fa68d5830494e141238a291d34 Mon Sep 17 00:00:00 2001 From: Anton Jurisevic Date: Fri, 29 Jun 2018 11:52:05 +1000 Subject: [PATCH 19/22] Pretty --- contracts/Nomin.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/Nomin.sol b/contracts/Nomin.sol index 08e8762c49..abbd12aec5 100644 --- a/contracts/Nomin.sol +++ b/contracts/Nomin.sol @@ -14,7 +14,7 @@ date: 2018-05-29 ----------------------------------------------------------------- MODULE DESCRIPTION ----------------------------------------------------------------- - +----------------------------------------------------------------- Havven-backed nomin stablecoin contract. @@ -25,8 +25,8 @@ value of their havvens to issue H * Cmax nomins. Where Cmax is some value less than 1. A configurable fee is charged on nomin transfers and deposited -into a common pot, which havven holders may withdraw from once per -fee period. +into a common pot, which havven holders may withdraw from once +per fee period. ----------------------------------------------------------------- */ From 26450e700805be57c1da9c42c4d7927e39164813 Mon Sep 17 00:00:00 2001 From: Anton Jurisevic Date: Fri, 29 Jun 2018 12:02:05 +1000 Subject: [PATCH 20/22] Add several issuance tests, fix bug. --- contracts/Havven.sol | 2 +- tests/test_Issuance.py | 133 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 125 insertions(+), 10 deletions(-) diff --git a/contracts/Havven.sol b/contracts/Havven.sol index 1d1d5e497d..2dc3f142ad 100644 --- a/contracts/Havven.sol +++ b/contracts/Havven.sol @@ -424,7 +424,7 @@ contract Havven is ExternStateToken { returns (bool) { address sender = messageSender; - require(nominsIssued[sender] == 0 || value <= transferableHavvens(from)); + require(nominsIssued[from] == 0 || value <= transferableHavvens(from)); /* Perform the transfer: if there is a problem, * an exception will be thrown in this call. */ _transferFrom_byProxy(sender, from, to, value); diff --git a/tests/test_Issuance.py b/tests/test_Issuance.py index f1bbe27f6e..cba932c9d9 100644 --- a/tests/test_Issuance.py +++ b/tests/test_Issuance.py @@ -2,7 +2,7 @@ W3, MASTER, UNIT, attempt, attempt_deploy, compile_contracts, mine_txs, mine_tx, - fast_forward, fresh_account, + fast_forward, fresh_account, fresh_accounts, take_snapshot, restore_snapshot ) from utils.testutils import HavvenTestCase, ZERO_ADDRESS, block_time @@ -180,7 +180,6 @@ def test_burn(self): self.assertEqual(self.nomin.balanceOf(alice), 0) def test_transfer_locked_havvens(self): - self.assertTrue(False) alice, bob = fresh_accounts(2) self.havven.endow(MASTER, alice, 500 * UNIT) @@ -190,25 +189,141 @@ def test_transfer_locked_havvens(self): self.havven_updatePrice(self.havven.oracle(), UNIT, self.havven.currentTime() + 1) self.havven.setIssuanceRatio(MASTER, UNIT) + self.havven.issueNomins(alice, 400 * UNIT) + self.havven.transfer(alice, bob, 500 * UNIT) + self.havven.endow(MASTER, alice, 500 * UNIT) + + self.havven.issueNomins(alice, 100 * UNIT) + self.havven.transfer(alice, bob, 500 * UNIT) + self.havven.endow(MASTER, alice, 500 * UNIT) + self.havven.issueNomins(alice, 100 * UNIT) + self.assertReverts(self.havven.transfer, alice, bob, 500 * UNIT) + self.havven.transfer(alice, bob, 400 * UNIT) + self.havven.endow(MASTER, alice, 400 * UNIT) + self.havven.issueNomins(alice, 100 * UNIT) + self.assertReverts(self.havven.transfer, alice, bob, 300 * UNIT + 1) + self.havven.transfer(alice, bob, 300 * UNIT) + self.havven.endow(MASTER, alice, 300 * UNIT) + + self.havven.issueNomins(alice, 300 * UNIT) + self.assertReverts(self.havven.transfer, alice, bob, 1) def test_transferFrom_locked_havvens(self): - self.assertTrue(False) + alice, bob, charlie = fresh_accounts(3) + self.havven.approve(alice, charlie, 2**256 - 1) + self.havven.endow(MASTER, alice, 500 * UNIT) + + self.havven.endow(MASTER, self.escrow.contract.address, 500 * UNIT) + self.escrow.appendVestingEntry(MASTER, alice, block_time() + 10000000, 500 * UNIT) + self.havven.setIssuer(MASTER, alice, True) + self.havven_updatePrice(self.havven.oracle(), UNIT, self.havven.currentTime() + 1) + self.havven.setIssuanceRatio(MASTER, UNIT) + + self.havven.issueNomins(alice, 400 * UNIT) + self.havven.transferFrom(charlie, alice, bob, 500 * UNIT) + self.havven.endow(MASTER, alice, 500 * UNIT) + + self.havven.issueNomins(alice, 100 * UNIT) + self.havven.transferFrom(charlie, alice, bob, 500 * UNIT) + self.havven.endow(MASTER, alice, 500 * UNIT) + + self.havven.issueNomins(alice, 100 * UNIT) + self.assertReverts(self.havven.transferFrom, charlie, alice, bob, 500 * UNIT) + self.havven.transferFrom(charlie, alice, bob, 400 * UNIT) + self.havven.endow(MASTER, alice, 400 * UNIT) + + self.havven.issueNomins(alice, 100 * UNIT) + self.assertReverts(self.havven.transferFrom, charlie, alice, bob, 300 * UNIT + 1) + self.havven.transferFrom(charlie, alice, bob, 300 * UNIT) + self.havven.endow(MASTER, alice, 300 * UNIT) + + self.havven.issueNomins(alice, 300 * UNIT) + self.assertReverts(self.havven.transferFrom, charlie, alice, bob, 1) def test_collateral(self): - self.assertTrue(False) + alice, bob, charlie, debbie = fresh_accounts(4) + self.havven.endow(MASTER, alice, UNIT) + self.havven.endow(MASTER, bob, UNIT) + self.havven.endow(MASTER, self.escrow.contract.address, 2 * UNIT) + self.escrow.appendVestingEntry(MASTER, alice, block_time() + 10000000, UNIT) + self.escrow.appendVestingEntry(MASTER, charlie, block_time() + 10000000, UNIT) + + self.assertEqual(self.havven.collateral(alice), 2 * UNIT) + self.assertEqual(self.havven.collateral(bob), UNIT) + self.assertEqual(self.havven.collateral(charlie), UNIT) + self.assertEqual(self.havven.collateral(debbie), 0) + + def test_collateral_no_escrow_contract(self): + alice, bob, charlie, debbie = fresh_accounts(4) + self.havven.endow(MASTER, alice, UNIT) + self.havven.endow(MASTER, bob, UNIT) + self.havven.endow(MASTER, self.escrow.contract.address, 2 * UNIT) + self.escrow.appendVestingEntry(MASTER, alice, block_time() + 10000000, UNIT) + self.escrow.appendVestingEntry(MASTER, charlie, block_time() + 10000000, UNIT) + self.havven.setEscrow(MASTER, ZERO_ADDRESS) + + self.assertEqual(self.havven.collateral(alice), UNIT) + self.assertEqual(self.havven.collateral(bob), UNIT) + self.assertEqual(self.havven.collateral(charlie), 0) + self.assertEqual(self.havven.collateral(debbie), 0) def test_issuanceDraft(self): - self.assertTrue(False) + alice = fresh_account() + self.havven.setIssuer(MASTER, alice, True) + self.havven.endow(MASTER, alice, 100 * UNIT) + self.havven_updatePrice(self.havven.oracle(), UNIT, self.havven.currentTime() + 1) + self.havven.issueNomins(alice, 5 * UNIT) + + self.assertEqual(self.havven.issuanceDraft(alice), 100 * UNIT) + self.havven_updatePrice(self.havven.oracle(), 2 * UNIT, self.havven.currentTime() + 2) + self.assertEqual(self.havven.issuanceDraft(alice), 50 * UNIT) + self.havven_updatePrice(self.havven.oracle(), UNIT // 2, self.havven.currentTime() + 3) + self.assertEqual(self.havven.issuanceDraft(alice), 200 * UNIT) def test_lockedCollateral(self): - self.assertTrue(False) + alice = fresh_account() + self.havven.setIssuer(MASTER, alice, True) + self.havven.endow(MASTER, alice, 100 * UNIT) + self.havven_updatePrice(self.havven.oracle(), UNIT, self.havven.currentTime() + 1) + self.havven.issueNomins(alice, 5 * UNIT) + + self.assertEqual(self.havven.lockedCollateral(alice), 100 * UNIT) + self.havven_updatePrice(self.havven.oracle(), 2 * UNIT, self.havven.currentTime() + 2) + self.assertEqual(self.havven.lockedCollateral(alice), 50 * UNIT) + self.havven_updatePrice(self.havven.oracle(), UNIT // 2, self.havven.currentTime() + 3) + self.assertEqual(self.havven.lockedCollateral(alice), 100 * UNIT) def test_unlockedCollateral(self): - self.assertTrue(False) + alice = fresh_account() + self.havven.setIssuer(MASTER, alice, True) + self.havven.endow(MASTER, alice, 100 * UNIT) + self.havven_updatePrice(self.havven.oracle(), UNIT, self.havven.currentTime() + 1) + self.havven.issueNomins(alice, 5 * UNIT) - def test_transferableHavvens(self): - self.assertTrue(False) + self.assertEqual(self.havven.unlockedCollateral(alice), 0 * UNIT) + self.havven_updatePrice(self.havven.oracle(), 2 * UNIT, self.havven.currentTime() + 2) + self.assertEqual(self.havven.unlockedCollateral(alice), 50 * UNIT) + self.havven_updatePrice(self.havven.oracle(), UNIT // 2, self.havven.currentTime() + 3) + self.assertEqual(self.havven.unlockedCollateral(alice), 0 * UNIT) + def test_transferableHavvens(self): + alice = fresh_account() + self.havven.setIssuer(MASTER, alice, True) + self.havven.endow(MASTER, alice, 300 * UNIT) + self.havven.endow(MASTER, self.escrow.contract.address, 100 * UNIT) + self.escrow.appendVestingEntry(MASTER, alice, block_time() + 10000000, 100 * UNIT) + self.havven_updatePrice(self.havven.oracle(), UNIT, self.havven.currentTime() + 1) + self.havven.issueNomins(alice, 5 * UNIT) + + self.assertEqual(self.havven.transferableHavvens(alice), 300 * UNIT) + self.havven_updatePrice(self.havven.oracle(), 2 * UNIT, self.havven.currentTime() + 2) + self.assertEqual(self.havven.transferableHavvens(alice), 300 * UNIT) + self.havven_updatePrice(self.havven.oracle(), UNIT // 2, self.havven.currentTime() + 3) + self.assertEqual(self.havven.transferableHavvens(alice), 200 * UNIT) + self.havven_updatePrice(self.havven.oracle(), UNIT // 4, self.havven.currentTime() + 4) + self.assertEqual(self.havven.transferableHavvens(alice), 0 * UNIT) + self.havven_updatePrice(self.havven.oracle(), UNIT // 8, self.havven.currentTime() + 5) + self.assertEqual(self.havven.transferableHavvens(alice), 0 * UNIT) From 9ae23c89de59982812fffa26968abc0cadb3feeb Mon Sep 17 00:00:00 2001 From: Anton Jurisevic Date: Fri, 29 Jun 2018 12:12:52 +1000 Subject: [PATCH 21/22] Fix test formatting. --- tests/test_ExternStateToken.py | 1 + tests/test_FeeToken.py | 1 + tests/test_HavvenEscrow.py | 1 + 3 files changed, 3 insertions(+) diff --git a/tests/test_ExternStateToken.py b/tests/test_ExternStateToken.py index 3d782a278e..56dd1cec2e 100644 --- a/tests/test_ExternStateToken.py +++ b/tests/test_ExternStateToken.py @@ -80,6 +80,7 @@ def test_constructor(self): def test_change_state(self): lucky_one = fresh_account() + print() # Deploy contract and old tokenstate _old_tokenstate, _ = attempt_deploy(self.compiled, 'TokenState', MASTER, diff --git a/tests/test_FeeToken.py b/tests/test_FeeToken.py index d1dd83326f..b8c49c02f9 100644 --- a/tests/test_FeeToken.py +++ b/tests/test_FeeToken.py @@ -91,6 +91,7 @@ def test_constructor(self): def test_change_state(self): lucky_one = fresh_account() + print() # Deploy contract and old tokenstate _old_tokenstate, _ = attempt_deploy(self.compiled, 'TokenState', MASTER, diff --git a/tests/test_HavvenEscrow.py b/tests/test_HavvenEscrow.py index 80d459e76a..9bb47349c9 100644 --- a/tests/test_HavvenEscrow.py +++ b/tests/test_HavvenEscrow.py @@ -658,6 +658,7 @@ def test_swap_havven(self): self.assertEqual(self.havven.balanceOf(alice), 25 * UNIT) self.assertEqual(self.havven.balanceOf(self.escrow_contract.address), 175 * UNIT) + print() # Deploy the new havven contract, with proxy and all. havven_proxy, _ = attempt_deploy(self.compiled, 'Proxy', MASTER, [MASTER]) havven_contract, _ = attempt_deploy(self.compiled, 'PublicHavven', MASTER, [havven_proxy.address, self.havven_token_state.address, MASTER, MASTER, UNIT//2, [], ZERO_ADDRESS]) From 3fd8e90e3277d4f3813c8d7a766a5b2ddaf7d6ce Mon Sep 17 00:00:00 2001 From: Anton Jurisevic Date: Fri, 29 Jun 2018 12:26:16 +1000 Subject: [PATCH 22/22] Ensure fee address can't be unfrozen. --- contracts/Nomin.sol | 2 +- tests/test_Nomin.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/contracts/Nomin.sol b/contracts/Nomin.sol index abbd12aec5..e23fbce7de 100644 --- a/contracts/Nomin.sol +++ b/contracts/Nomin.sol @@ -173,7 +173,7 @@ contract Nomin is FeeToken { external optionalProxy_onlyOwner { - require(frozen[target] && target != address(this)); + require(frozen[target] && target != FEE_ADDRESS); frozen[target] = false; emitAccountUnfrozen(target); } diff --git a/tests/test_Nomin.py b/tests/test_Nomin.py index 66865a88c5..4fa2637f10 100644 --- a/tests/test_Nomin.py +++ b/tests/test_Nomin.py @@ -571,8 +571,9 @@ def test_freezeAndConfiscate(self): def test_unfreezeAccount(self): target = fresh_account() - # The nomin contract itself should not be unfreezable. - self.assertReverts(self.nomin.unfreezeAccount, MASTER, self.nomin_contract.address) + # The fee address should not be unfreezable. + self.assertTrue(self.nomin.frozen(self.nomin.FEE_ADDRESS())) + self.assertReverts(self.nomin.unfreezeAccount, MASTER, self.nomin.FEE_ADDRESS()) self.assertTrue(self.nomin.frozen(self.nomin.FEE_ADDRESS())) # Unfreezing non-frozen accounts should not do anything.