]> Git Repo - VerusCoin.git/commitdiff
Fix initial chain definition at PBaaS activation
authormiketout <[email protected]>
Sun, 12 Apr 2020 05:08:43 +0000 (22:08 -0700)
committermiketout <[email protected]>
Sun, 12 Apr 2020 05:08:43 +0000 (22:08 -0700)
src/miner.cpp
src/pbaas/crosschainrpc.cpp
src/pbaas/crosschainrpc.h
src/pbaas/identity.h
src/pbaas/pbaas.cpp
src/pbaas/reserves.cpp
src/pbaas/reserves.h
src/rpc/pbaasrpc.cpp
src/script/script.cpp
src/script/script.h
src/wallet/wallet.cpp

index e1390ee8e94f2b6075f9688ab0f77b3212a58272..297c8ceb903d40cb95c7f9ba32d258cae9424538 100644 (file)
@@ -313,6 +313,11 @@ CPubKey GetScriptPublicKey(const CScript &scriptPubKey)
 
 void ProcessNewImports(const uint160 &sourceChainID, const CTransaction &lastConfirmed, int32_t nHeight)
 {
+    if (CConstVerusSolutionVector::GetVersionByHeight(nHeight) < CActivationHeight::ACTIVATE_PBAAS || 
+        CConstVerusSolutionVector::activationHeight.IsActivationHeight(CActivationHeight::ACTIVATE_PBAAS, nHeight))
+    {
+        return;
+    }
     uint32_t consensusBranchId = CurrentEpochBranchId(nHeight, Params().GetConsensus());
 
     // get any pending imports from the source chain. if the source chain is this chain, we don't need notarization
index 55a62d41c920991b4b33522c52e2eaeb4d279ab5..a4a2bc4def6fafae60a0749242c202920e7cc294 100644 (file)
@@ -348,6 +348,31 @@ UniValue CNodeData::ToUniValue() const
     return obj;
 }
 
+uint160 CurrencyNameToChainID(std::string currencyStr)
+{
+    std::string extraName;
+    uint160 retVal;
+    currencyStr = TrimSpaces(currencyStr);
+    if (!currencyStr.size())
+    {
+        return retVal;
+    }
+    ParseSubNames(currencyStr, extraName, true);
+    if (currencyStr.back() == '@' || extraName != "")
+    {
+        return retVal;
+    }
+    CTxDestination currencyDest = DecodeDestination(currencyStr);
+    if (currencyDest.which() == COptCCParams::ADDRTYPE_INVALID)
+    {
+        currencyDest = DecodeDestination(currencyStr + "@");
+    }
+    if (currencyDest.which() != COptCCParams::ADDRTYPE_INVALID)
+    {
+        retVal = GetDestinationID(currencyDest);
+    }
+    return retVal;
+}
 
 CCurrencyDefinition::CCurrencyDefinition(const UniValue &obj)
 {
@@ -355,14 +380,9 @@ CCurrencyDefinition::CCurrencyDefinition(const UniValue &obj)
     {
         nVersion = PBAAS_VERSION;
         name = std::string(uni_get_str(find_value(obj, "name")), 0, (KOMODO_ASSETCHAIN_MAXLEN - 1));
-        name = CleanName(name, parent);
 
         std::string parentStr = uni_get_str(find_value(obj, "parent"));
-        if (parentStr == "")
-        {
-            parent = parent;
-        }
-        else
+        if (parentStr != "")
         {
             CTxDestination parentDest = DecodeDestination(parentStr);
             parent = GetDestinationID(parentDest);
@@ -373,6 +393,8 @@ CCurrencyDefinition::CCurrencyDefinition(const UniValue &obj)
             }
         }
 
+        name = CleanName(name, parent);
+
         options = (uint32_t)uni_get_int64(find_value(obj, "options"));
 
         idRegistrationAmount = AmountFromValueNoErr(find_value(obj, "idregistrationprice"));
@@ -405,20 +427,8 @@ CCurrencyDefinition::CCurrencyDefinition(const UniValue &obj)
         startBlock = uni_get_int(find_value(obj, "startblock"));
         endBlock = uni_get_int(find_value(obj, "endblock"));
 
-        proofProtocol = (EProofProtocol)uni_get_int(find_value(obj, "proofprotocol"));
-        notarizationProtocol = (ENotarizationProtocol)uni_get_int(find_value(obj, "notarizationprotocol"));
-        if (proofProtocol == PROOF_INVALID)
-        {
-            // default to standard PBaaS for a blockchain and ID for a token
-            proofProtocol = options & OPTION_TOKEN ? PROOF_CHAINID : PROOF_PBAASMMR;
-        }
-
-        if (notarizationProtocol == NOTARIZATION_INVALID)
-        {
-            // default to standard PBaaS for a blockchain and ID for a token
-            notarizationProtocol = options & OPTION_TOKEN ? NOTARIZATION_NOTARY_CHAINID : NOTARIZATION_AUTO;
-        }
-
+        proofProtocol = (EProofProtocol)uni_get_int(find_value(obj, "proofprotocol"), (int32_t)PROOF_PBAASMMR);
+        notarizationProtocol = (ENotarizationProtocol)uni_get_int(find_value(obj, "notarizationprotocol"), (int32_t)NOTARIZATION_AUTO);
         int32_t totalReserveWeight = AmountFromValueNoErr(find_value(obj, "reserveratio"));
         UniValue currencyArr = find_value(obj, "currencies");
         UniValue weightArr = find_value(obj, "weights");
@@ -542,8 +552,7 @@ CCurrencyDefinition::CCurrencyDefinition(const UniValue &obj)
 
             for (int i = 0; nVersion != PBAAS_VERSION_INVALID && i < currencyArr.size(); i++)
             {
-                uint160 currencyID;
-                currencyID = GetDestinationID(DecodeDestination(uni_get_str(currencyArr[i])));
+                uint160 currencyID = CurrencyNameToChainID(uni_get_str(currencyArr[i]));
                 // if we have a destination, but it is invalid, the json for this definition cannot be valid
                 if (currencyID.IsNull())
                 {
@@ -611,7 +620,6 @@ CCurrencyDefinition::CCurrencyDefinition(const UniValue &obj)
             }
         }
 
-        launchFee = AmountFromValueNoErr(find_value(obj, "launchfee"));
         preAllocationRatio = AmountFromValueNoErr(find_value(obj, "preallocationratio"));
 
         UniValue preallocationArr = find_value(obj, "preallocation");
@@ -624,23 +632,24 @@ CCurrencyDefinition::CCurrencyDefinition(const UniValue &obj)
                 if (preallocationKey.size() != 1 || preallocationValue.size() != 1)
                 {
                     LogPrintf("%s: each preallocation entry must contain one destination identity and one amount\n", __func__);
+                    printf("%s: each preallocation entry must contain one destination identity and one amount\n", __func__);
                     nVersion = PBAAS_VERSION_INVALID;
                     break;
                 }
 
                 CTxDestination preallocDest = DecodeDestination(preallocationKey[0]);
 
-                if (preallocDest.which() != COptCCParams::ADDRTYPE_INVALID && preallocDest.which() != COptCCParams::ADDRTYPE_ID)
+                if (preallocDest.which() != COptCCParams::ADDRTYPE_ID && preallocDest.which() != COptCCParams::ADDRTYPE_INVALID)
                 {
-                    LogPrintf("%s: preallocation must be allocated to IDs\n", __func__);
+                    LogPrintf("%s: preallocation destination must be an identity\n", __func__);
                     nVersion = PBAAS_VERSION_INVALID;
                     break;
                 }
 
                 CAmount preAllocAmount = AmountFromValueNoErr(preallocationValue[0]);
-                if (preAllocAmount < 0)
+                if (preAllocAmount <= 0)
                 {
-                    LogPrintf("%s: preallocation must be greater than zero\n", __func__);
+                    LogPrintf("%s: preallocation values must be greater than zero\n", __func__);
                     nVersion = PBAAS_VERSION_INVALID;
                     break;
                 }
@@ -834,8 +843,6 @@ UniValue CCurrencyDefinition::ToUniValue() const
         obj.push_back(Pair("maxpreconversion", maxPreconvertArr));
     }
 
-    obj.push_back(Pair("launchfee", launchFee));
-
     if (preAllocationRatio)
     {
         obj.push_back(Pair("preallocationratio", ValueFromAmount(preAllocationRatio)));
@@ -850,7 +857,7 @@ UniValue CCurrencyDefinition::ToUniValue() const
             onePreAlloc.push_back(Pair(EncodeDestination(CIdentityID(onePreAllocation.first)), ValueFromAmount(onePreAllocation.second)));
             preAllocationArr.push_back(onePreAlloc);
         }
-        obj.push_back(Pair("preallocations", preAllocationArr));
+        obj.push_back(Pair("preallocation", preAllocationArr));
     }
 
     if (contributions.size())
index fa74d77264cf82d2d57efb88452626f27a847afc..069394c4f9343f57363cb81c45b3cfc3f5791a38 100644 (file)
@@ -156,6 +156,8 @@ public:
 class CCurrencyDefinition
 {
 public:
+    static const int64_t DEFAULT_ID_REGISTRATION_AMOUNT = 10000000000;
+
     enum ELimitsDefaults
     {
         MIN_PER_BLOCK_NOTARIZATION = 1000000, // 0.01 VRSC per block notarization minimum
@@ -163,7 +165,6 @@ public:
         MIN_BILLING_PERIOD = 960,           // 16 hour minimum billing period for notarization, typically expect days/weeks/months
         MIN_CURRENCY_LIFE = 480,            // 8 hour minimum lifetime, which gives 8 hours of minimum billing to notarize conclusion
         DEFAULT_OUTPUT_VALUE = 0,           // 0 VRSC default output value
-        DEFAULT_ID_REGISTRATION_AMOUNT = 10000000000,
         DEFAULT_ID_REFERRAL_LEVELS = 3
     };
 
@@ -206,8 +207,8 @@ public:
     // the interface to the currency controller. systemID refers to the controlling blockchain or currency that serves as a gateway
     uint160 systemID;                       // native system of currency home, for BTC.VRSC: BTC, for VQUAD.VRSC: QUAD.VRSC, for QUAD.VRSC, QUAD.VRSC
     CTransferDestination nativeCurrencyID;  // ID of the currency in its native system
-    ENotarizationProtocol notarizationProtocol; // method of notarization
-    EProofProtocol proofProtocol;           // method of proving imports and other elements
+    int32_t notarizationProtocol;           // method of notarization
+    int32_t proofProtocol;                  // method of proving imports and other elements
 
     int64_t idRegistrationAmount;           // normal cost of ID registration
     int32_t idReferralLevels;               // number of referral levels to divide among
@@ -231,7 +232,6 @@ public:
     std::vector<int64_t> minPreconvert;     // can be used for Kickstarter-like launch and return all non-network fees upon failure to meet minimum
     std::vector<int64_t> maxPreconvert;     // maximum amount of each reserve that can be pre-converted
 
-    int32_t launchFee;                      // fee in ratio deducted from purchase before conversion. always 100000000 (100%) for non-reserve currencies
     int32_t preAllocationRatio;             // if non-zero, a ratio of the initial supply instead of a fixed number is used to calculate total preallocation
     std::vector<std::pair<uint160, int64_t>> preAllocation; // pre-allocation recipients, from pre-allocation/premine, emitted after reserve weights are set
     std::vector<int64_t> contributions;     // initial contributions
@@ -259,7 +259,7 @@ public:
                         ENotarizationProtocol NotarizationProtocol, EProofProtocol ProofProtocol, int64_t IDRegistrationAmount, int32_t IDReferralLevels,
                         const std::vector<uint160> &Notaries, int32_t MinNotariesConfirm, int32_t BillingPeriod, int64_t NotaryReward,
                         int32_t StartBlock, int32_t EndBlock, std::vector<uint160> Currencies, std::vector<int32_t> Weights, 
-                        std::vector<int64_t> Conversions, std::vector<int64_t> MinPreconvert, std::vector<int64_t> MaxPreconvert, int32_t LaunchFee,
+                        std::vector<int64_t> Conversions, std::vector<int64_t> MinPreconvert, std::vector<int64_t> MaxPreconvert,
                         int32_t PreAllocationRatio, std::vector<std::pair<uint160, int64_t>> PreAllocation, std::vector<int64_t> Contributions,
                         std::vector<int64_t> Preconverted, const std::vector<int64_t> &chainRewards, const std::vector<int64_t> &chainRewardsDecay,
                         const std::vector<int32_t> &chainHalving, const std::vector<int32_t> &chainEraEnd) :
@@ -284,7 +284,6 @@ public:
                         conversions(Conversions),
                         minPreconvert(MinPreconvert),
                         maxPreconvert(MaxPreconvert),
-                        launchFee(LaunchFee),
                         preAllocationRatio(PreAllocationRatio),
                         preAllocation(PreAllocation),
                         contributions(Contributions),
@@ -305,12 +304,13 @@ public:
     template <typename Stream, typename Operation>
     inline void SerializationOp(Stream& s, Operation ser_action) {
         READWRITE(nVersion);
+        READWRITE(options);        
         READWRITE(parent);        
         READWRITE(name);        
         READWRITE(systemID);
         READWRITE(nativeCurrencyID);
-        READWRITE(VARINT((int32_t)notarizationProtocol));
-        READWRITE(VARINT((int32_t)proofProtocol));
+        READWRITE(notarizationProtocol);
+        READWRITE(proofProtocol);
         READWRITE(VARINT(idRegistrationAmount));
         READWRITE(VARINT(idReferralLevels));
         READWRITE(notaries);
@@ -324,7 +324,6 @@ public:
         READWRITE(conversions);
         READWRITE(minPreconvert);
         READWRITE(maxPreconvert);
-        READWRITE(VARINT(launchFee));
         READWRITE(VARINT(preAllocationRatio));
         READWRITE(preAllocation);
         READWRITE(contributions);
@@ -382,7 +381,7 @@ public:
 
     bool IsToken() const
     {
-        return !(ChainOptions() & OPTION_TOKEN);
+        return ChainOptions() & OPTION_TOKEN;
     }
 
     void SetToken(bool isToken)
index 6063e0b0ecaf8acc342f4581920305d0d87ffc70..c5a9964f095e365a5bfd703040124b07eb82c2b8 100644 (file)
@@ -452,7 +452,8 @@ public:
         if (parent != newIdentity.parent ||
             name != newIdentity.name ||
             (newIdentity.flags & ~(FLAG_REVOKED) != 0 && newIdentity.nVersion == VERSION_FIRSTVALID) ||
-            (newIdentity.flags & ~(FLAG_REVOKED + FLAG_ACTIVECURRENCY) != 0 && newIdentity.nVersion == VERSION_PBAAS) ||
+            (newIdentity.flags & ~(FLAG_REVOKED + FLAG_ACTIVECURRENCY) != 0 && newIdentity.nVersion >= VERSION_PBAAS) ||
+            (flags & FLAG_ACTIVECURRENCY != 0 && newIdentity.flags & FLAG_ACTIVECURRENCY == 0) ||
             newIdentity.nVersion < VERSION_FIRSTVALID ||
             newIdentity.nVersion > VERSION_LASTVALID)
         {
index b26a0daa015b577330810f070316db02f0ac5675..5f12a241353f0d2515125e8efbcf460f999a568c 100644 (file)
@@ -412,10 +412,10 @@ CCurrencyDefinition::CCurrencyDefinition(const CTransaction &tx)
 {
     bool definitionFound = false;
     nVersion = PBAAS_VERSION_INVALID;
-    for (auto out : tx.vout)
+    for (auto &out : tx.vout)
     {
         COptCCParams p;
-        if (IsPayToCryptoCondition(out.scriptPubKey, p))
+        if (out.scriptPubKey.IsPayToCryptoCondition(p) && p.IsValid())
         {
             if (p.evalCode == EVAL_CURRENCY_DEFINITION)
             {
index a8f02f5226df7bb2ab9f1a1cd3ea15e841d84fb8..e8e0e5085109a56ac8f95fd10aa99b90f79d7c12 100644 (file)
@@ -384,7 +384,7 @@ UniValue CTokenOutput::ToUniValue() const
 {
     UniValue ret(UniValue::VOBJ);
     ret.push_back(Pair("version", (int64_t)nVersion));
-    ret.push_back(Pair("currencyid", EncodeDestination(CKeyID(currencyID))));
+    ret.push_back(Pair("currencyid", EncodeDestination(CIdentityID(currencyID))));
     ret.push_back(Pair("value", ValueFromAmount(nValue)));
     return ret;
 }
@@ -425,9 +425,7 @@ UniValue CReserveTransfer::ToUniValue() const
     return ret;
 }
 
-CCurrencyValueMap CReserveTransfer::CalculateFee(uint32_t flags, 
-                                                 const uint160 &nativeSource, 
-                                                 CAmount transferTotal) const
+CCurrencyValueMap CReserveTransfer::CalculateFee(uint32_t flags, CAmount transferTotal) const
 {
     CCurrencyValueMap feeMap;
 
@@ -437,7 +435,7 @@ CCurrencyValueMap CReserveTransfer::CalculateFee(uint32_t flags,
         return feeMap;
     }
 
-    feeMap.valueMap[nativeSource] = CReserveTransfer::DEFAULT_PER_STEP_FEE << 1 +
+    feeMap.valueMap[currencyID] = CReserveTransfer::DEFAULT_PER_STEP_FEE << 1 +
                                     ((CReserveTransfer::DEFAULT_PER_STEP_FEE << 1) * (destination.destination.size() / DESTINATION_BYTE_DIVISOR));
 
     // add conversion fees in source currency for preconvert
@@ -449,6 +447,12 @@ CCurrencyValueMap CReserveTransfer::CalculateFee(uint32_t flags,
     return feeMap;
 }
 
+CAmount CReserveTransfer::CalculateTransferFee(const CTransferDestination &destination)
+{
+    return CReserveTransfer::DEFAULT_PER_STEP_FEE << 1 +
+                ((CReserveTransfer::DEFAULT_PER_STEP_FEE << 1) * (destination.destination.size() / DESTINATION_BYTE_DIVISOR));
+}
+
 CAmount CReserveTransfer::CalculateTransferFee() const
 {
     // determine fee for this send
@@ -456,9 +460,7 @@ CAmount CReserveTransfer::CalculateTransferFee() const
     {
         return 0;
     }
-
-    return CReserveTransfer::DEFAULT_PER_STEP_FEE << 1 +
-                ((CReserveTransfer::DEFAULT_PER_STEP_FEE << 1) * (destination.destination.size() / DESTINATION_BYTE_DIVISOR));
+    return CalculateTransferFee(destination);
 }
 
 CReserveExchange::CReserveExchange(const UniValue &uni) : CTokenOutput(uni)
@@ -1542,6 +1544,7 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction
 
     CNameReservation nameReservation;
     CIdentity identity;
+    CCurrencyDefinition newCurrencyDef;
 
     flags |= IS_VALID;
 
@@ -1676,7 +1679,7 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction
                     // either a fully valid import with an export or the first import either in block 1 or the chain definition
                     // on the Verus chain
                     if ((nHeight == 1 && tx.IsCoinBase() && !IsVerusActive()) ||
-                        (CCurrencyDefinition(tx).IsValid() && IsVerusActive()) ||
+                        ((newCurrencyDef = CCurrencyDefinition(tx)).IsValid() && IsVerusActive()) ||
                         (tx.vout.back().scriptPubKey.IsOpReturn() &&
                         (chainObjs = RetrieveOpRetArray(tx.vout.back().scriptPubKey)).size() == 1 &&
                         chainObjs[0]->objectType == CHAINOBJ_CROSSCHAINPROOF))
@@ -1715,6 +1718,17 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction
                                 flags |= IS_REJECT;
                             }
                         }
+                        // if this is a new currency definition, the currency def is the source of the pre-allocated output
+                        // that will be "transferred" to the chain and materialize when the chain starts, assuming it met any
+                        // minimums, etc.
+                        if (newCurrencyDef.IsValid() && newCurrencyDef.IsToken() && newCurrencyDef.preAllocation.size())
+                        {
+                            // if we have pre-allocation, consider the output of pre-allocation the source of input to this transaction
+                            for (auto &onePreAlloc : newCurrencyDef.preAllocation)
+                            {
+                                AddReserveInput(newCurrencyDef.GetID(), onePreAlloc.second);
+                            }
+                        }
                     }
                     else
                     {
@@ -1746,6 +1760,12 @@ CReserveTransactionDescriptor::CReserveTransactionDescriptor(const CTransaction
                     flags |= IS_EXPORT;
                 }
                 break;
+
+                case EVAL_CURRENCY_DEFINITION:
+                {
+
+                }
+                break;
             }
         }
     }
@@ -1877,8 +1897,8 @@ bool CReserveTransactionDescriptor::AddReserveTransferImportOutputs(const uint16
                 }
 
                 // includes all conversion fees of other currencies as well
-                CCurrencyValueMap thisExpectedFees = curTransfer.CalculateFee(curTransfer.flags, currencySourceID, curTransfer.nValue);
-                if (curTransfer.nFees < thisExpectedFees.valueMap[currencySourceID])
+                CCurrencyValueMap thisExpectedFees = curTransfer.CalculateFee(curTransfer.flags, curTransfer.nValue);
+                if (curTransfer.nFees < thisExpectedFees.valueMap[curTransfer.currencyID])
                 {
                     printf("%s: Incorrect fee sent with export %s\n", __func__, curTransfer.ToUniValue().write().c_str());
                     LogPrintf("%s: Incorrect fee sent with export %s\n", __func__, curTransfer.ToUniValue().write().c_str());
@@ -1987,7 +2007,7 @@ bool CReserveTransactionDescriptor::AddReserveTransferImportOutputs(const uint16
                     // naturally compress a full ID to an ID destination, since it is going back where it came from
                     CTxDestination sendBackAddr = TransferDestinationToDestination(curTransfer.destination);
 
-                    CAmount fees = curTransfer.CalculateFee(curTransfer.flags, currencySourceID, curTransfer.nValue).valueMap.begin()->second;
+                    CAmount fees = curTransfer.CalculateFee(curTransfer.flags, curTransfer.nValue).valueMap.begin()->second;
 
                     CReserveTransfer rt = CReserveTransfer(CReserveExchange::VALID, 
                                                            curTransfer.currencyID, 
index bb4be46e43d3d39a33a953243dbff62432b6f5f1..767101a920ec44730edf27c2ad56560a4cf593b4 100644 (file)
@@ -176,7 +176,7 @@ public:
 
     uint32_t flags;                         // type of transfer and options
     CAmount nFees;                          // cross-chain network fees only, separated out to enable market conversions, conversion fees are additional
-    uint160 destCurrencyID;                       // system to export to, which may represent a PBaaS chain or external bridge
+    uint160 destCurrencyID;                 // system to export to, which may represent a PBaaS chain or external bridge
     CTransferDestination destination;       // system specific address to send funds to on the target chain
 
     CReserveTransfer(const std::vector<unsigned char> &asVector)
@@ -207,9 +207,9 @@ public:
 
     UniValue ToUniValue() const;
 
-    CCurrencyValueMap CalculateFee(uint32_t flags, 
-                                   const uint160 &nativeSource, 
-                                   CAmount transferTotal) const;
+    CCurrencyValueMap CalculateFee(uint32_t flags, CAmount transferTotal) const;
+
+    static CAmount CalculateTransferFee(const CTransferDestination &destination);
 
     CAmount CalculateTransferFee() const;
 
@@ -336,7 +336,7 @@ public:
 
     bool IsValid() const
     {
-        return nVersion > VERSION_INVALID && nVersion <= VERSION_LAST && !systemID.IsNull() && importValue.valueMap.size() != 0;
+        return nVersion > VERSION_INVALID && nVersion <= VERSION_LAST && !systemID.IsNull();
     }
 
     UniValue ToUniValue() const;
@@ -391,7 +391,6 @@ public:
         return nVersion > VERSION_INVALID && 
                nVersion <= VERSION_LAST && 
                !systemID.IsNull() && 
-               totalAmounts.valueMap.size() && 
                totalAmounts.valueMap.size() == totalFees.valueMap.size();
     }
 
index 1da36901a5960f5495c9fbd626b565985b9ce2ec..0aa7d6c5ac46e14276414ea32b5d842dd82b7300 100644 (file)
@@ -816,7 +816,7 @@ uint160 ValidateCurrencyName(std::string currencyStr, CCurrencyDefinition *pCurr
         return retVal;
     }
     ParseSubNames(currencyStr, extraName, true);
-    if (currencyStr.back() == '@' || extraName != "")
+    if (currencyStr.back() == '@' || (extraName != "" && boost::to_lower_copy(extraName) != boost::to_lower_copy(VERUS_CHAINNAME)))
     {
         return retVal;
     }
@@ -866,7 +866,6 @@ UniValue getcurrencydefinition(const UniValue& params, bool fHelp)
             "    \"chainid\" : \"hex-string\",    (string) 40 char string that represents the chain ID, calculated from the name\n"
             "    \"premine\" : \"n\",             (int) amount of currency paid out to the premine address in block #1, may be smart distribution\n"
             "    \"convertible\" : \"xxxx\"       (bool) if this currency is a fractional reserve currency of Verus\n"
-            "    \"launchfee\" : \"n\",           (int) (launchfee * total converted) / 100000000 sent directly to premine address\n"
             "    \"startblock\" : \"n\",          (int) block # on this chain, which must be notarized into block one of the chain\n"
             "    \"endblock\" : \"n\",            (int) block # after which, this chain's useful life is considered to be over\n"
             "    \"eras\" : \"[obj, ...]\",       (objarray) different chain phases of rewards and convertibility\n"
@@ -1264,7 +1263,6 @@ UniValue getdefinedchains(const UniValue& params, bool fHelp)
             "    \"chainid\" : \"hex-string\",    (string) 40 char string that represents the chain ID, calculated from the name\n"
             "    \"premine\" : \"n\",             (int) amount of currency paid out to the premine address in block #1, may be smart distribution\n"
             "    \"convertible\" : \"xxxx\"       (bool) if this currency is a fractional reserve currency of Verus\n"
-            "    \"launchfee\" : \"n\",           (int) (launchfee * total converted) / 100000000 sent directly to premine address\n"
             "    \"startblock\" : \"n\",          (int) block # on this chain, which must be notarized into block one of the chain\n"
             "    \"endblock\" : \"n\",            (int) block # after which, this chain's useful life is considered to be over\n"
             "    \"eras\" : \"[obj, ...]\",       (objarray) different chain phases of rewards and convertibility\n"
@@ -3320,6 +3318,8 @@ UniValue getlatestimportsout(const UniValue& params, bool fHelp)
         );
     }
 
+    UniValue ret(UniValue::VARR);
+
     // starting from that last transaction id, see if we have any newer to export for the indicated chain, and if so, return them as
     // import transactions using the importtxtemplate as a template
     CheckPBaaSAPIsValid();
@@ -3330,7 +3330,7 @@ UniValue getlatestimportsout(const UniValue& params, bool fHelp)
 
     if (chainID.IsNull())
     {
-        throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid chain name or chain ID");
+        return ret;
     }
 
     // starting from that last transaction id, see if we have any newer to export for the indicated chain, and if so, return them as
@@ -3339,7 +3339,7 @@ UniValue getlatestimportsout(const UniValue& params, bool fHelp)
 
     if (!GetCurrencyDefinition(chainID, chainDef))
     {
-        throw JSONRPCError(RPC_INVALID_PARAMETER, "Chain definition not found");
+        return ret;
     }
 
     std::string lastImportHex = uni_get_str(find_value(params[0], "lastimporttx"));
@@ -3365,7 +3365,7 @@ UniValue getlatestimportsout(const UniValue& params, bool fHelp)
           chainObjs[0]->objectType == CHAINOBJ_CROSSCHAINPROOF))))
     {
         DeleteOpRetObjects(chainObjs);
-        throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid last import tx");
+        return ret;
     }
 
     DeleteOpRetObjects(chainObjs);
@@ -3373,9 +3373,8 @@ UniValue getlatestimportsout(const UniValue& params, bool fHelp)
     std::vector<CTransaction> newImports;
     if (!ConnectedChains.CreateLatestImports(chainDef, lastImportTx, templateTx, lastConfirmedNotarization, tokenImportAvailable, nativeImportAvailable, newImports))
     {
-        throw JSONRPCError(RPC_INVALID_PARAMETER, "Failure creating new imports");
+        return ret;
     }
-    UniValue ret(UniValue::VARR);
 
     for (auto import : newImports)
     {
@@ -3602,7 +3601,7 @@ bool RefundFailedLaunch(uint160 currencyID, CTransaction &lastImportTx, std::vec
                     {
                         CReserveTransfer &rt = ((CChainObject<CReserveTransfer> *)objPtr)->object;
 
-                        // convert full ID destinations to normal ID outputs, full ID is on this chain already
+                        // convert full ID destinations to normal ID outputs, since it's refund, full ID will be on this chain already
                         if (rt.destination.type == CTransferDestination::DEST_FULLID)
                         {
                             CIdentity(rt.destination.destination);
@@ -3622,7 +3621,7 @@ bool RefundFailedLaunch(uint160 currencyID, CTransaction &lastImportTx, std::vec
                         }
                         else
                         {
-                            CCurrencyValueMap fees = rt.CalculateFee(rt.flags, ASSETCHAINS_CHAINID, rt.nValue + rt.nFees);
+                            CCurrencyValueMap fees = rt.CalculateFee(rt.flags, rt.nValue + rt.nFees);
                             if (fees.valueMap.size() == 1)
                             {
                                 ccx.totalFees.valueMap[rt.currencyID] += rt.nFees;
@@ -3997,7 +3996,7 @@ UniValue definecurrency(const UniValue& params, bool fHelp)
             "         \"options\" : \"n\",             (int,    optional) bits:\n"
             "                                                             1 = FRACTIONAL, 2 = IDRESTRICTED, 4 = IDSTAKING, 8 = IDREFERRALS\n"
             "                                                             0x10 = IDREFERRALSREQUIRED, 0x20 = TOKEN, 0x40 = CANBERESERVE\n"
-            "         \"identityname\" : \"xxxx\",     (string, required) existing identity with no active or pending blockchain as the name\n"
+            "         \"name\" : \"xxxx\",             (string, required) name of existing identity with no active or pending blockchain\n"
             "         \"idregistrationprice\" : \"xx.xx\", (value, required) price of an identity in native currency\n"
             "         \"idreferrallevels\" : \"n\",    (int, required) how many levels ID referrals go back in reward\n"
 
@@ -4015,7 +4014,6 @@ UniValue definecurrency(const UniValue& params, bool fHelp)
             "         \"minpreconvert\" : \"[\"xx.xx\",..]\", (list, optional) must be same size as currencies. minimum in each currency to launch\n"
             "         \"maxpreconvert\" : \"[\"xx.xx\",..]\", (list, optional) maximum in each currency allowed\n"
 
-            "         \"launchfee\"    : \"xx.xx\",    (value,  optional) % fee for conversion at pre-launch\n"
             "         \"preallocationratio\" : \"xx.xx\", (value, optional) if non-0, pre-allocation is a percentage after initial supply is determined\n"
             "         \"preallocation\" : \"[{\"identity\":xx.xx}..]\", (list, optional) amount or % of from pre-allocation, depending on preallocationratio\n"
             "         \"initialcontribution\" : \"[\"xx.xx\",..]\", (list, optional) initial contribution in each currency\n"
@@ -4174,66 +4172,68 @@ UniValue definecurrency(const UniValue& params, bool fHelp)
                                                " blocks after startblock (" + to_string(newChain.startBlock) + ")\n");
     }
 
-    if (newChain.billingPeriod < CCurrencyDefinition::MIN_BILLING_PERIOD || (newChain.notarizationReward / newChain.billingPeriod) < CCurrencyDefinition::MIN_PER_BLOCK_NOTARIZATION)
+    if (!newChain.IsToken())
     {
-        throw JSONRPCError(RPC_INVALID_PARAMS, "Billing period of at least " + 
-                                               to_string(CCurrencyDefinition::MIN_BILLING_PERIOD) + 
-                                               " blocks and per-block notary rewards of >= " + to_string(CCurrencyDefinition::MIN_PER_BLOCK_NOTARIZATION) + 
-                                               " are required to define an active currency\n");
-    }
+        if (newChain.billingPeriod < CCurrencyDefinition::MIN_BILLING_PERIOD || (newChain.notarizationReward / newChain.billingPeriod) < CCurrencyDefinition::MIN_PER_BLOCK_NOTARIZATION)
+        {
+            throw JSONRPCError(RPC_INVALID_PARAMS, "Billing period of at least " + 
+                                                to_string(CCurrencyDefinition::MIN_BILLING_PERIOD) + 
+                                                " blocks and per-block notary rewards of >= " + to_string(CCurrencyDefinition::MIN_PER_BLOCK_NOTARIZATION) + 
+                                                " are required to define an active currency\n");
+        }
 
-    // TODO: check to see if rewards obviously lead to an unstable currency
-    //for (int i = 0; i < newChain.rewards.size(); i++)
-    //{
-    //}
+        // TODO: check to see if rewards obviously lead to an unstable currency
+        //for (int i = 0; i < newChain.rewards.size(); i++)
+        //{
+        //}
 
-    // if we have no emission parameters, this is not a PBaaS blockchain, it is a controlled or bridged token.
-    // controlled tokens can be centrally or algorithmically controlled.
-    if (newChain.rewards.empty() && !newChain.IsToken())
-    {
-        throw JSONRPCError(RPC_INVALID_PARAMS, "A currency must either be based on a token protocol or must specify blockchain rewards, even if 0\n");
-    }
+        // if we have no emission parameters, this is not a PBaaS blockchain, it is a controlled or bridged token.
+        // controlled tokens can be centrally or algorithmically controlled.
+        if (newChain.rewards.empty())
+        {
+            throw JSONRPCError(RPC_INVALID_PARAMS, "A currency must either be based on a token protocol or must specify blockchain rewards, even if 0\n");
+        }
 
-    if ((newChain.rewards.empty() || newChain.currencies.empty()) && newChain.IsReserve())
-    {
-        throw JSONRPCError(RPC_INVALID_PARAMS, "Fractional reserve currencies must specify blockchain rewards, even if 0 and at least one reserve currency\n");
-    }
+        if (newChain.currencies.empty() && newChain.IsReserve())
+        {
+            throw JSONRPCError(RPC_INVALID_PARAMS, "Fractional reserve currencies must specify blockchain rewards, even if 0 and at least one reserve currency\n");
+        }
 
-    // if this is a fractional reserve currency, ensure that all reserves are currently active 
-    // with at least as long of a life as this currency and that at least one of the currencies
-    // is VRSC or VRSCTEST.
-    std::vector<CCurrencyDefinition> reserveCurrencies;
-    bool hasCoreReserve = false;
-    if (newChain.IsReserve())
-    {
-        for (auto &currency : newChain.currencies)
+        // if this is a fractional reserve currency, ensure that all reserves are currently active 
+        // with at least as long of a life as this currency and that at least one of the currencies
+        // is VRSC or VRSCTEST.
+        std::vector<CCurrencyDefinition> reserveCurrencies;
+        bool hasCoreReserve = false;
+        if (newChain.IsReserve())
         {
-            reserveCurrencies.emplace_back();
-            if (!GetCurrencyDefinition(currency, reserveCurrencies.back()))
+            for (auto &currency : newChain.currencies)
             {
-                throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot find reserve currency " + EncodeDestination(CKeyID(currency)));
-            }
+                reserveCurrencies.emplace_back();
+                if (!GetCurrencyDefinition(currency, reserveCurrencies.back()))
+                {
+                    throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot find reserve currency " + EncodeDestination(CKeyID(currency)));
+                }
 
-            if (reserveCurrencies.back().endBlock && (!newChain.endBlock || reserveCurrencies.back().endBlock < newChain.endBlock))
-            {
-                throw JSONRPCError(RPC_INVALID_PARAMETER, "Reserve currency " + EncodeDestination(CKeyID(currency)) + " ends its life before the fractional currency's endblock");
-            }
+                if (reserveCurrencies.back().endBlock && (!newChain.endBlock || reserveCurrencies.back().endBlock < newChain.endBlock))
+                {
+                    throw JSONRPCError(RPC_INVALID_PARAMETER, "Reserve currency " + EncodeDestination(CKeyID(currency)) + " ends its life before the fractional currency's endblock");
+                }
 
-            if (!reserveCurrencies.back().CanBeReserve())
-            {
-                throw JSONRPCError(RPC_INVALID_PARAMETER, "Currency " + EncodeDestination(CKeyID(currency)) + " may not be used as a reserve");
-            }
+                if (!reserveCurrencies.back().CanBeReserve())
+                {
+                    throw JSONRPCError(RPC_INVALID_PARAMETER, "Currency " + EncodeDestination(CKeyID(currency)) + " may not be used as a reserve");
+                }
 
-            if (currency == VERUS_CHAINID)
-            {
-                hasCoreReserve = true;
+                if (currency == VERUS_CHAINID)
+                {
+                    hasCoreReserve = true;
+                }
             }
         }
-    }
-
-    if (!hasCoreReserve)
-    {
-        throw JSONRPCError(RPC_INVALID_PARAMETER, "Fractional currency requires a reserve of " + VERUS_CHAINNAME + " in addition to any other reserves");
+        if (!hasCoreReserve)
+        {
+            throw JSONRPCError(RPC_INVALID_PARAMETER, "Fractional currency requires a reserve of " + VERUS_CHAINNAME + " in addition to any other reserves");
+        }
     }
 
     // now, create the outputs:
@@ -4382,12 +4382,14 @@ UniValue definecurrency(const UniValue& params, bool fHelp)
     dests = std::vector<CTxDestination>({CPubKey(ParseHex(CC.CChexstr))});
     indexDests = std::vector<CTxDestination>({CKeyID(CCrossChainRPCData::GetConditionID(newChainID, EVAL_CROSSCHAIN_EXPORT))});
     CCrossChainExport ccx = CCrossChainExport(newChainID, 0, CCurrencyValueMap(), CCurrencyValueMap());
-    vOutputs.push_back({MakeMofNCCScript(CConditionObj<CCrossChainExport>(EVAL_CROSSCHAIN_IMPORT, dests, 1, &ccx), &indexDests), 0, false});
+    vOutputs.push_back({MakeMofNCCScript(CConditionObj<CCrossChainExport>(EVAL_CROSSCHAIN_EXPORT, dests, 1, &ccx), &indexDests), 0, false});
 
+    std::set<CIdentityID> idExportSet;
     if (!newChain.IsToken())
     {
-        // create identity exports for launch identity, notaries, and preallocation recipients
-        std::set<CIdentityID> idExportSet = {newChainID};
+        idExportSet = std::set<CIdentityID>({newChainID});
+
+        // create chain transfer exports for launch identity, notaries, and preallocation recipients
         for (auto &notary : newChain.notaries)
         {
             idExportSet.insert(notary);
@@ -4397,7 +4399,7 @@ UniValue definecurrency(const UniValue& params, bool fHelp)
             idExportSet.insert(oneAlloc.first);
         }
 
-        // now, look them all up and create the exports
+        // now, look them all up and create exports for zero value to move the IDs
         for (auto &oneID : idExportSet)
         {
             CIdentity oneIdentity = (oneID == newChainID) ? launchIdentity : CIdentity::LookupIdentity(oneID);
@@ -4405,19 +4407,54 @@ UniValue definecurrency(const UniValue& params, bool fHelp)
             {
                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid specified identity: " + EncodeDestination(CIdentityID(oneID)));
             }
-            CIdentityExport cie = CIdentityExport(oneID, ::GetHash(oneIdentity), thisChainID, CIdentityExport::DEFAULT_EXPORT_FEE, newChainID);
 
-            cp = CCinit(&CC, EVAL_IDENTITY_EXPORT);
-            CPubKey pk(ParseHex(CC.CChexstr));
-
-            indexDests = std::vector<CTxDestination>({CKeyID(newChain.GetConditionID(EVAL_IDENTITY_EXPORT))});
-            dests = std::vector<CTxDestination>({pk});
-
-            vOutputs.push_back({MakeMofNCCScript(CConditionObj<CIdentityExport>(EVAL_IDENTITY_EXPORT, dests, 1, &cie), &indexDests), 
-                                                 CIdentityExport::DEFAULT_EXPORT_FEE, 
+            // emit a reserve exchange output
+            cp = CCinit(&CC, EVAL_RESERVE_TRANSFER);
+            CPubKey pk = CPubKey(ParseHex(CC.CChexstr));
+
+            // send a zero output to this ID and pass the full ID to do so
+            std::vector<CTxDestination> dests = std::vector<CTxDestination>({pk.GetID()});
+            indexDests = std::vector<CTxDestination>({CKeyID(CCrossChainRPCData::GetConditionID(newChain.systemID, EVAL_RESERVE_TRANSFER))});
+
+            CTransferDestination transferDest = IdentityToTransferDestination(oneIdentity);
+            CReserveTransfer rt = CReserveTransfer(CReserveExchange::VALID, 
+                                                   ASSETCHAINS_CHAINID, 
+                                                   0, 
+                                                   CReserveTransfer::CalculateTransferFee(transferDest), 
+                                                   newChain.systemID,
+                                                   transferDest);
+
+            vOutputs.push_back({MakeMofNCCScript(CConditionObj<CReserveTransfer>(EVAL_RESERVE_TRANSFER, dests, 1, &rt), &indexDests), 
+                                                 rt.nFees, 
                                                  false});
         }
-    }    
+    }
+    else
+    {
+        // output preallocation
+        for (auto &oneAlloc : newChain.preAllocation)
+        {
+            // emit a reserve exchange output
+            cp = CCinit(&CC, EVAL_RESERVE_TRANSFER);
+            CPubKey pk = CPubKey(ParseHex(CC.CChexstr));
+
+            // send a zero output to this ID and pass the full ID to do so
+            std::vector<CTxDestination> dests = std::vector<CTxDestination>({pk.GetID()});
+            indexDests = std::vector<CTxDestination>({CKeyID(CCrossChainRPCData::GetConditionID(newChain.systemID, EVAL_RESERVE_TRANSFER))});
+
+            CTransferDestination transferDest = DestinationToTransferDestination(CIdentityID(oneAlloc.first));
+            CReserveTransfer rt = CReserveTransfer(CReserveExchange::VALID, 
+                                                   newChain.GetID(), 
+                                                   oneAlloc.second, 
+                                                   CReserveTransfer::CalculateTransferFee(transferDest), 
+                                                   ASSETCHAINS_CHAINID,
+                                                   transferDest);
+
+            vOutputs.push_back({MakeMofNCCScript(CConditionObj<CReserveTransfer>(EVAL_RESERVE_TRANSFER, dests, 1, &rt), &indexDests), 
+                                                 rt.nFees, 
+                                                 false});
+        }
+    }
 
     // make the outputs for initial contributions
     if (newChain.contributions.size() && newChain.contributions.size() == newChain.currencies.size())
index 603542ac9376829bbb2725c21d60b765136f4836..23adb6cb3c1c44c87f7a023207909c58ecbf6bb2 100644 (file)
@@ -234,6 +234,25 @@ CTransferDestination DestinationToTransferDestination(const CTxDestination &dest
     return retDest;
 }
 
+CTransferDestination IdentityToTransferDestination(const CIdentity &identity)
+{
+    return CTransferDestination(CTransferDestination::DEST_FULLID, ::AsVector(identity));
+}
+
+CIdentity TransferDestinationToIdentity(const CTransferDestination &dest)
+{
+    CIdentity retIdentity;
+    switch (dest.type)
+    {
+        case CTransferDestination::DEST_FULLID:
+        {
+            ::FromVector(dest.destination, retIdentity);
+            break;
+        }        
+    }
+    return retIdentity;
+}
+
 std::vector<CTxDestination> TransferDestinationsToDestinations(const std::vector<CTransferDestination> &transferDests)
 {
     std::vector<CTxDestination> retDests;
index 78b7d2374619245cbfd787a059dd8f531fce8a94..edfcb90437df895f3455a113ee0669b3ab328b07 100644 (file)
@@ -29,6 +29,7 @@
 #define OPRETTYPE_STAKEPARAMS2 6
 
 class CCurrencyStateNew;
+class CIdentity;
 
 static const unsigned int MAX_SCRIPT_ELEMENT_SIZE_V2 = 1024;
 static const unsigned int MAX_SCRIPT_ELEMENT_SIZE_IDENTITY = 3073;    // fulfillment maximum size + 1, MAKE SURE TO KEEP MAX_BINARY_CC_SIZE IN SYNC WITH THIS-1, BUF_SIZE in crypto conditions, should be >=
@@ -419,6 +420,8 @@ typedef boost::variant<CNoDestination, CPubKey, CKeyID, CScriptID, CIdentityID,
 
 CTxDestination TransferDestinationToDestination(const CTransferDestination &trasnferDest);
 CTransferDestination DestinationToTransferDestination(const CTxDestination &dest);
+CTransferDestination IdentityToTransferDestination(const CIdentity &identity);
+CIdentity TransferDestinationToIdentity(const CTransferDestination &dest);
 std::vector<CTxDestination> TransferDestinationsToDestinations(const std::vector<CTransferDestination> &transferDests);
 std::vector<CTransferDestination> DestinationsToTransferDestinations(const std::vector<CTxDestination> &dests);
 
index f2a611bdae486c422739548eea9d140977ead8cf..617dbff64922de0866681b326616d890e1c70614 100644 (file)
@@ -4750,7 +4750,8 @@ void CWallet::AvailableReserveCoins(vector<COutput>& vCoins, bool fOnlyConfirmed
             for (int i = 0; i < pcoin->vout.size(); i++)
             {
                 isminetype mine = IsMine(pcoin->vout[i]);
-                if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO &&
+                if (!(IsSpent(wtxid, i)) &&
+                    mine != ISMINE_NO &&
                     !IsLockedCoin((*it).first, i) &&
                     (!coinControl || !coinControl->HasSelected() || coinControl->IsSelected((*it).first, i)))
                 {
@@ -4787,7 +4788,8 @@ void CWallet::AvailableReserveCoins(vector<COutput>& vCoins, bool fOnlyConfirmed
                     // don't return zero valued outputs
                     if (rOut.valueMap.size() || pcoin->vout[i].nValue)
                     {
-                        if ((pOnlyTheseCurrencies && pOnlyTheseCurrencies->Intersects(rOut)) || (fIncludeNative && pcoin->vout[i].nValue))
+                        if ((rOut.valueMap.size() && (!pOnlyTheseCurrencies || (pOnlyTheseCurrencies && pOnlyTheseCurrencies->Intersects(rOut)))) || 
+                            (fIncludeNative && pcoin->vout[i].nValue))
                         {
                             vCoins.push_back(COutput(pcoin, i, nDepth, (mine & ISMINE_SPENDABLE) != ISMINE_NO));
                         }
@@ -5359,7 +5361,8 @@ bool CWallet::SelectReserveCoins(const CCurrencyValueMap& targetReserveValues,
             ++it;
     }
     retval = false;
-    if ( targetReserveValues <= targetReserveValues.IntersectingValues(valueFromPresetInputs) && targetNativeValue <= nativeValueFromPresets )
+    if ( targetNativeValue <= nativeRet &&
+         targetReserveValues <= targetReserveValues.IntersectingValues(valueFromPresetInputs) && targetNativeValue <= nativeValueFromPresets )
         retval = true;
     else if ( SelectReserveCoinsMinConf(targetReserveValues, targetNativeValue, 1, 6, vCoins, setCoinsRet, valueRet, nativeRet) != 0 )
         retval = true;
@@ -5792,12 +5795,7 @@ bool CWallet::CreateReserveTransaction(const vector<CRecipient>& vecSend, CWalle
     // fees can only be deducted from fractional reserve outputs on fractional currency blockchains, otherwise,
     // Verus/Verustest must be used to cover fees.
     bool isVerusActive = IsVerusActive();
-    if (IsVerusActive())
-    {
-        strFailReason = _("Transactions that accept reserve currency input can only be created on PBaaS blockchains");
-        return false;
-    }
-    else
+    if (!isVerusActive)
     {
         if (ConnectedChains.ReserveCurrencies().size())
         {
@@ -5815,9 +5813,21 @@ bool CWallet::CreateReserveTransaction(const vector<CRecipient>& vecSend, CWalle
         return false;
     }
 
+    CCurrencyDefinition newCurrency;
+
     // make sure that there are recipients, all recipients expect reserve inputs, and amounts are all non-negative
     BOOST_FOREACH (const CRecipient& recipient, vecSend)
     {
+        COptCCParams p;
+        if (recipient.scriptPubKey.IsPayToCryptoCondition(p) && p.IsValid() && p.evalCode == EVAL_CURRENCY_DEFINITION && p.vData.size() >= 1)
+        {
+            if (newCurrency.IsValid())
+            {
+                strFailReason = _("A normal transaction cannot define define multiple currencies");
+                return false;
+            }
+            newCurrency = CCurrencyDefinition(p.vData[0]);
+        }
         CCurrencyValueMap values = recipient.scriptPubKey.ReserveOutValue();
         CCurrencyValueMap zeroes = values - values; // zero values of the same currencies
 
@@ -5831,6 +5841,7 @@ bool CWallet::CreateReserveTransaction(const vector<CRecipient>& vecSend, CWalle
             strFailReason = _("Transaction output amounts must not be negative");
             return false;
         }
+
         totalNativeOutput += recipient.nAmount;
         totalReserveOutput += values;
 
@@ -5853,6 +5864,11 @@ bool CWallet::CreateReserveTransaction(const vector<CRecipient>& vecSend, CWalle
         }
     }
 
+    if (newCurrency.IsValid())
+    {
+        totalReserveOutput.valueMap.erase(newCurrency.GetID());
+    }
+
     wtxNew.fTimeReceivedIsTxTime = true;
     wtxNew.BindWallet(this);
     int nextBlockHeight = chainActive.Height() + 1;
@@ -5990,7 +6006,6 @@ bool CWallet::CreateReserveTransaction(const vector<CRecipient>& vecSend, CWalle
                             p.evalCode == EVAL_RESERVE_OUTPUT || 
                             p.evalCode == EVAL_RESERVE_DEPOSIT || 
                             p.evalCode == EVAL_RESERVE_EXCHANGE || 
-                            p.evalCode == EVAL_RESERVE_TRANSFER ||
                             p.evalCode == EVAL_NONE)
                         {
                             // add all values to a native equivalent
This page took 0.079181 seconds and 4 git commands to generate.