/****************************************************************************** * Copyright © 2013-2016 The Nxt Core Developers. * * * * See the AUTHORS.txt, DEVELOPER-AGREEMENT.txt and LICENSE.txt files at * * the top-level directory of this distribution for the individual copyright * * holder information and the developer policies on copyright and licensing. * * * * Unless otherwise agreed in a custom licensing agreement, no part of the * * Nxt software, including this file, may be copied, modified, propagated, * * or distributed except according to the terms contained in the LICENSE.txt * * file. * * * * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ package nxt.http.monetarysystem; import nxt.Account; import nxt.BlockchainTest; import nxt.Constants; import nxt.CurrencyType; import nxt.crypto.Crypto; import nxt.http.APICall; import nxt.util.Convert; import nxt.util.Logger; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.junit.Assert; import org.junit.Test; public class TestCurrencyReserveAndClaim extends BlockchainTest { @Test public void reserveIncrease() { APICall apiCall = new TestCurrencyIssuance.Builder(). type(CurrencyType.RESERVABLE.getCode() | CurrencyType.EXCHANGEABLE.getCode()). issuanceHeight(baseHeight + 5). minReservePerUnitNQT((long) 1). initialSupply((long)0). reserveSupply((long)100000). build(); String currencyId = TestCurrencyIssuance.issueCurrencyApi(apiCall); reserveIncreaseImpl(currencyId, ALICE.getSecretPhrase(), BOB.getSecretPhrase()); } @Test public void cancelCrowdFunding() { APICall apiCall1 = new TestCurrencyIssuance.Builder(). type(CurrencyType.RESERVABLE.getCode() | CurrencyType.EXCHANGEABLE.getCode()). issuanceHeight(baseHeight + 4). minReservePerUnitNQT((long) 11). initialSupply((long)0). reserveSupply((long)100000). build(); String currencyId = TestCurrencyIssuance.issueCurrencyApi(apiCall1); long balanceNQT1 = ALICE.getBalance(); long balanceNQT2 = BOB.getBalance(); reserveIncreaseImpl(currencyId, ALICE.getSecretPhrase(), BOB.getSecretPhrase()); generateBlock(); // cancellation of crowd funding because of insufficient funds APICall apiCall = new APICall.Builder("getCurrencyFounders"). feeNQT(Constants.ONE_NXT). param("currency", currencyId). build(); JSONObject getFoundersResponse = apiCall.invoke(); Logger.logMessage("getFoundersResponse: " + getFoundersResponse); Assert.assertTrue(((JSONArray)getFoundersResponse.get("founders")).size() == 0); Assert.assertEquals(balanceNQT1 - Constants.ONE_NXT, ALICE.getBalance()); Assert.assertEquals(balanceNQT2 - 2*Constants.ONE_NXT, BOB.getBalance()); } @Test public void crowdFundingDistribution() { APICall apiCall = new TestCurrencyIssuance.Builder(). type(CurrencyType.RESERVABLE.getCode() | CurrencyType.EXCHANGEABLE.getCode()). initialSupply((long) 0). reserveSupply((long) 100000). issuanceHeight(baseHeight + 4). minReservePerUnitNQT((long) 10). build(); String currencyId = TestCurrencyIssuance.issueCurrencyApi(apiCall); long balanceNQT1 = ALICE.getBalance(); long balanceNQT2 = BOB.getBalance(); reserveIncreaseImpl(currencyId, ALICE.getSecretPhrase(), BOB.getSecretPhrase()); generateBlock(); // distribution of currency to founders Assert.assertEquals(20000, ALICE.getCurrencyUnits(Convert.parseAccountId(currencyId))); Assert.assertEquals(80000, BOB.getCurrencyUnits(Convert.parseAccountId(currencyId))); Assert.assertEquals(balanceNQT1 - Constants.ONE_NXT - 200000 + (100000*10), ALICE.getBalance()); Assert.assertEquals(balanceNQT2 - 2*Constants.ONE_NXT - 800000, BOB.getBalance()); } @Test public void crowdFundingDistributionRounding() { APICall apiCall = new TestCurrencyIssuance.Builder(). type(CurrencyType.RESERVABLE.getCode() | CurrencyType.EXCHANGEABLE.getCode()). initialSupply((long)0). reserveSupply((long)24). maxSupply((long) 24). issuanceHeight(baseHeight + 4). minReservePerUnitNQT((long) 10). build(); String currencyId = TestCurrencyIssuance.issueCurrencyApi(apiCall); long balanceNQT1 = ALICE.getBalance(); long balanceNQT2 = BOB.getBalance(); long balanceNQT3 = CHUCK.getBalance(); reserveIncreaseImpl(currencyId, BOB.getSecretPhrase(), CHUCK.getSecretPhrase()); generateBlock(); // distribution of currency to founders // account 2 balance round(24 * 0.2) = round(4.8) = 4 // account 3 balance round(24 * 0.8) = round(19.2) = 19 // issuer receives the leftover of 1 Assert.assertEquals(4, BOB.getCurrencyUnits(Convert.parseAccountId(currencyId))); Assert.assertEquals(19, CHUCK.getCurrencyUnits(Convert.parseAccountId(currencyId))); Assert.assertEquals(1, ALICE.getCurrencyUnits(Convert.parseAccountId(currencyId))); Assert.assertEquals(balanceNQT1 + 24 * 10, ALICE.getBalance()); Assert.assertEquals(balanceNQT2 - Constants.ONE_NXT - 24 * 2, BOB.getBalance()); Assert.assertEquals(balanceNQT3 - 2 * Constants.ONE_NXT - 24 * 8, CHUCK.getBalance()); apiCall = new APICall.Builder("getCurrency"). param("currency", currencyId). build(); JSONObject response = apiCall.invoke(); Assert.assertEquals("24", response.get("currentSupply")); } public void reserveIncreaseImpl(String currencyId, String secret1, String secret2) { APICall apiCall = new APICall.Builder("currencyReserveIncrease"). secretPhrase(secret1). feeNQT(Constants.ONE_NXT). param("currency", currencyId). param("amountPerUnitNQT", "" + 2). build(); JSONObject reserveIncreaseResponse = apiCall.invoke(); Logger.logMessage("reserveIncreaseResponse: " + reserveIncreaseResponse); generateBlock(); // Two increase reserve transactions in the same block apiCall = new APICall.Builder("currencyReserveIncrease"). secretPhrase(secret2). feeNQT(Constants.ONE_NXT). param("currency", currencyId). param("amountPerUnitNQT", "" + 3). build(); reserveIncreaseResponse = apiCall.invoke(); Logger.logMessage("reserveIncreaseResponse: " + reserveIncreaseResponse); apiCall = new APICall.Builder("currencyReserveIncrease"). secretPhrase(secret2). feeNQT(Constants.ONE_NXT). param("currency", currencyId). param("amountPerUnitNQT", "" + 5). build(); reserveIncreaseResponse = apiCall.invoke(); Logger.logMessage("reserveIncreaseResponse: " + reserveIncreaseResponse); generateBlock(); apiCall = new APICall.Builder("getCurrencyFounders"). feeNQT(Constants.ONE_NXT). param("currency", currencyId). build(); JSONObject getFoundersResponse = apiCall.invoke(); Logger.logMessage("getFoundersResponse: " + getFoundersResponse); JSONArray founders = (JSONArray)getFoundersResponse.get("founders"); JSONObject founder1 = (JSONObject)founders.get(0); Assert.assertTrue(Long.toUnsignedString(Account.getId(Crypto.getPublicKey(secret1))).equals(founder1.get("account")) || Long.toUnsignedString(Account.getId(Crypto.getPublicKey(secret2))).equals(founder1.get("account"))); Assert.assertTrue(String.valueOf(3L + 5L).equals(founder1.get("amountPerUnitNQT")) || String.valueOf(2L).equals(founder1.get("amountPerUnitNQT"))); JSONObject founder2 = (JSONObject)founders.get(1); Assert.assertTrue(Long.toUnsignedString(Account.getId(Crypto.getPublicKey(secret1))).equals(founder2.get("account")) || Long.toUnsignedString(Account.getId(Crypto.getPublicKey(secret2))).equals(founder2.get("account"))); Assert.assertTrue(String.valueOf(3L + 5L).equals(founder2.get("amountPerUnitNQT")) || String.valueOf(2L).equals(founder2.get("amountPerUnitNQT"))); } }