uint160 sourceSystemID = sourceSystem.GetID();
newNotarization = *this;
+ newNotarization.SetDefinitionNotarization(false);
newNotarization.prevNotarization = CUTXORef();
newNotarization.prevHeight = newNotarization.notarizationHeight;
newNotarization.notarizationHeight = currentHeight;
CCurrencyValueMap newReserveIn = CCurrencyValueMap(std::vector<uint160>({reserveTransfer.FirstCurrency()}),
std::vector<int64_t>({reserveTransfer.FirstValue() - fees.valueMap[reserveTransfer.FirstCurrency()]}));
CCurrencyValueMap newTotalReserves = CCurrencyValueMap(destCurrency.currencies, newNotarization.currencyState.reserves) + newReserveIn;
- if (newTotalReserves <= CCurrencyValueMap(destCurrency.currencies, destCurrency.maxPreconvert))
+ if (!destCurrency.maxPreconvert.size() || newTotalReserves <= CCurrencyValueMap(destCurrency.currencies, destCurrency.maxPreconvert))
{
newNotarization.currencyState.reserveIn =
(CCurrencyValueMap(destCurrency.currencies, newNotarization.currencyState.reserveIn) + newReserveIn).AsCurrencyVector(destCurrency.currencies);
// if this is the clear launch notarization after start, make the notarization and determine if we should launch or refund
if (destCurrency.launchSystemID == sourceSystemID && currentHeight == (destCurrency.startBlock - 1))
{
- // we get one pre-launch coming through here
- bool launchClear = false;
- if (newNotarization.IsPreLaunch() && !newNotarization.currencyState.IsLaunchClear())
+ // we get one pre-launch coming through here, initial supply is set and ready for pre-convert
+ // don't revert or emit initial supply, it will be emitted for valid pre-conversions, which must already
+ // be included in the currency state
+ if (newNotarization.IsPreLaunch() && !newNotarization.IsLaunchCleared())
{
newNotarization.SetPreLaunch(false);
+ newNotarization.SetLaunchCleared();
+
+ // do not revert initial fixed supply on a currency
+ assert(newNotarization.currencyState.nativeOut >= newNotarization.currencyState.initialSupply);
+
newNotarization.currencyState.RevertReservesAndSupply();
newNotarization.currencyState.SetPrelaunch(false);
newNotarization.currencyState.SetLaunchClear();
- // first time through is export, second is import, then we finish clearing the launch
- }
- else if (newNotarization.currencyState.IsLaunchClear())
- {
- launchClear = true;
- newNotarization.currencyState.SetLaunchClear(false);
- newNotarization.currencyState.SetPrelaunch(true);
- newNotarization.currencyState.ClearForNextBlock();
- }
- bool refunding = false;
-
- // check if the chain is qualified for a refund
- CCurrencyValueMap minPreMap, fees;
- CCurrencyValueMap preConvertedMap = CCurrencyValueMap(destCurrency.currencies, newNotarization.currencyState.reserves).CanonicalMap();
+ // first time through is export, second is import, then we finish clearing the launch
+ // check if the chain is qualified to launch or should refund
+ CCurrencyValueMap minPreMap, fees;
+ CCurrencyValueMap preConvertedMap = CCurrencyValueMap(destCurrency.currencies, newNotarization.currencyState.reserves).CanonicalMap();
- if (destCurrency.minPreconvert.size() && destCurrency.minPreconvert.size() == destCurrency.currencies.size())
- {
- minPreMap = CCurrencyValueMap(destCurrency.currencies, destCurrency.minPreconvert).CanonicalMap();
- }
+ if (destCurrency.minPreconvert.size() && destCurrency.minPreconvert.size() == destCurrency.currencies.size())
+ {
+ minPreMap = CCurrencyValueMap(destCurrency.currencies, destCurrency.minPreconvert).CanonicalMap();
+ }
- if (minPreMap.valueMap.size() && preConvertedMap < minPreMap)
- {
- // we force the supply to zero
- // in any case where there was less than minimum participation,
- newNotarization.currencyState.supply = 0;
- newNotarization.currencyState.SetRefunding(true);
- newNotarization.SetRefunding(true);
- refunding = true;
+ if (minPreMap.valueMap.size() && preConvertedMap < minPreMap)
+ {
+ // we force the supply to zero
+ // in any case where there was less than minimum participation,
+ newNotarization.currencyState.supply = 0;
+ newNotarization.currencyState.SetRefunding(true);
+ newNotarization.SetRefunding(true);
+ }
+ else
+ {
+ newNotarization.SetLaunchConfirmed();
+ newNotarization.currencyState.SetLaunchConfirmed();
+ }
}
- else
+ else if (newNotarization.IsLaunchCleared())
{
- newNotarization.SetLaunchConfirmed();
- newNotarization.currencyState.SetLaunchConfirmed();
+ newNotarization.currencyState.SetPrelaunch(false);
+ newNotarization.currencyState.SetLaunchClear(false);
+ newNotarization.currencyState.ClearForNextBlock();
}
CCurrencyDefinition destSystem = ConnectedChains.GetCachedCurrency(destCurrency.systemID);
gatewayDepositsUsed,
spentCurrencyOut,
&tempState);
-
+
newNotarization.currencyState = tempState;
- if (launchClear)
- {
- newNotarization.currencyState.SetPrelaunch(false);
- newNotarization.currencyState.SetLaunchClear(false);
- }
return retVal;
}
- else if (lastExportHeight >= destCurrency.startBlock)
+ else
{
- newNotarization.currencyState.SetLaunchClear(false);
- if (destCurrency.systemID != ASSETCHAINS_CHAINID)
+ if (lastExportHeight >= destCurrency.startBlock)
+ {
+ newNotarization.currencyState.SetLaunchCompleteMarker();
+ newNotarization.currencyState.SetLaunchClear(false);
+ if (destCurrency.systemID != ASSETCHAINS_CHAINID)
+ {
+ newNotarization.SetSameChain(false);
+ }
+ }
+ else
{
- newNotarization.SetSameChain(false);
+ newNotarization.currencyState.SetPrelaunch();
}
// calculate new state from processing all transfers
gatewayDepositsUsed,
spentCurrencyOut,
&newNotarization.currencyState);
- if (isValidExport && destCurrency.IsFractional())
+ if (!newNotarization.currencyState.IsPrelaunch() && isValidExport && destCurrency.IsFractional())
{
// we want the new price and the old state as a starting point to ensure no rounding error impact
// on reserves
currencyState = GetInitialCurrencyState(thisChain);
}
// if this is a token on this chain, it will be simply notarized
- else if (curDef.systemID == ASSETCHAINS_CHAINID)
+ else if (curDef.systemID == ASSETCHAINS_CHAINID || (curDef.launchSystemID == ASSETCHAINS_CHAINID && curDef.startBlock > height))
{
// get the last notarization in the height range for this currency, which is valid by definition for a token
CPBaaSNotarization notarization;
else
{
currencyState = GetInitialCurrencyState(curDef);
+ currencyState.SetPrelaunch();
}
}
- if (!currencyState.IsValid() || notarization.notarizationHeight < (curDef.startBlock - 1))
+ if (currencyState.IsValid() && notarization.notarizationHeight < (curDef.startBlock - 1))
{
// pre-launch
currencyState.SetPrelaunch(true);
// if not the initial import in the thread, it should have a valid prior notarization as well
// the notarization of the initial import may be superceded by pre-launch exports
- if (nHeight && lastCCI.IsInitialLaunchImport() || lastCCI.IsPostLaunch())
+ if (nHeight && lastCCI.IsPostLaunch())
{
if (!lastCCI.GetImportInfo(lastImportTx,
outputNum,
std::vector<CReserveTransfer> exportTransfers = oneIT.second;
std::vector<CTxOut> newOutputs;
CCurrencyValueMap importedCurrency, gatewayDepositsUsed, spentCurrencyOut;
- // if we are transisitioning from export to import, allow the function to set launch clear on the currency
+ // if we are transitioning from export to import, allow the function to set launch clear on the currency
if (lastNotarization.currencyState.IsLaunchClear() && !lastCCI.IsInitialLaunchImport())
{
lastNotarization.SetPreLaunch();
// dust rules don't apply
if (oneChangeVal.second)
{
- CReserveDeposit rd = CReserveDeposit(sourceSystemID, CCurrencyValueMap(std::vector<uint160>({oneChangeVal.first}),
- std::vector<int64_t>({oneChangeVal.second})));
- tb.AddTransparentOutput(MakeMofNCCScript(CConditionObj<CReserveDeposit>(EVAL_RESERVE_DEPOSIT, dests, 1, &rd)),
- oneChangeVal.first == ASSETCHAINS_CHAINID ? oneChangeVal.second : 0);
+ CReserveDeposit rd = CReserveDeposit(sourceSystemID, CCurrencyValueMap());;
+ CAmount nativeOutput = 0;
+ if (oneChangeVal.first == ASSETCHAINS_CHAINID)
+ {
+ nativeOutput = oneChangeVal.second;
+ }
+ else
+ {
+ rd.reserveValues.valueMap[oneChangeVal.first] = oneChangeVal.second;
+ }
+ tb.AddTransparentOutput(MakeMofNCCScript(CConditionObj<CReserveDeposit>(EVAL_RESERVE_DEPOSIT, dests, 1, &rd)), nativeOutput);
}
}
// dust rules don't apply
if (oneChangeVal.second)
{
- CReserveDeposit rd = CReserveDeposit(ccx.destCurrencyID, CCurrencyValueMap(std::vector<uint160>({oneChangeVal.first}),
- std::vector<int64_t>({oneChangeVal.second})));
- tb.AddTransparentOutput(MakeMofNCCScript(CConditionObj<CReserveDeposit>(EVAL_RESERVE_DEPOSIT, dests, 1, &rd)),
- oneChangeVal.first == ASSETCHAINS_CHAINID ? oneChangeVal.second : 0);
+ CReserveDeposit rd = CReserveDeposit(ccx.destCurrencyID, CCurrencyValueMap());;
+ CAmount nativeOutput = 0;
+ if (oneChangeVal.first == ASSETCHAINS_CHAINID)
+ {
+ nativeOutput = oneChangeVal.second;
+ }
+ else
+ {
+ rd.reserveValues.valueMap[oneChangeVal.first] = oneChangeVal.second;
+ }
+ tb.AddTransparentOutput(MakeMofNCCScript(CConditionObj<CReserveDeposit>(EVAL_RESERVE_DEPOSIT, dests, 1, &rd)), nativeOutput);
}
}
return false;
}
+ //printf("%s: num transfers %ld\n", __func__, exportTransfers.size());
+
newNotarization.prevNotarization = lastNotarizationUTXO;
CCurrencyValueMap totalExports;
addHeight,
destSystemID,
currencyID,
- txInputs.size(),
+ exportTransfers.size(),
totalExports.CanonicalMap(),
totalTransferFees.CanonicalMap(),
transferHash,
auto outputIt = transferOutputs.begin();
bool checkLaunchCurrencies = false;
for (int outputsDone = 0;
- outputsDone < transferOutputs.size() || launchCurrencies.size();
+ outputsDone <= transferOutputs.size() || launchCurrencies.size();
outputsDone++)
{
if (outputIt != transferOutputs.end())
if (!reserves.valueMap.size() && nativeAmount)
{
CTxDestination dest = TransferDestinationToDestination(destination);
- if (dest.which() == CScript::P2ID || dest.which() == CScript::P2PK || dest.which() == CScript::P2PKH || dest.which() == CScript::P2SH)
+ if (dest.which() == COptCCParams::ADDRTYPE_ID ||
+ dest.which() == COptCCParams::ADDRTYPE_PK ||
+ dest.which() == COptCCParams::ADDRTYPE_PKH ||
+ dest.which() == COptCCParams::ADDRTYPE_SH)
{
txOut = CTxOut(nativeAmount, GetScriptForDestination(dest));
return true;
else
{
CTxDestination dest = TransferDestinationToDestination(destination);
- if (dest.which() == CScript::P2ID || dest.which() == CScript::P2PK || dest.which() == CScript::P2PKH)
+ if (dest.which() == COptCCParams::ADDRTYPE_ID || dest.which() == COptCCParams::ADDRTYPE_PK || dest.which() == COptCCParams::ADDRTYPE_PKH)
{
std::vector<CTxDestination> dests = std::vector<CTxDestination>({TransferDestinationToDestination(destination)});
CTokenOutput ro = CTokenOutput(reserves);
return false;
}
- if (!importCurrencyState.IsPrelaunch())
+ if (importCurrencyState.IsLaunchCompleteMarker())
{
printf("%s: Invalid preconversion after launch %s\n", __func__, curTransfer.ToUniValue().write().c_str());
LogPrintf("%s: Invalid preconversion after launch %s\n", __func__, curTransfer.ToUniValue().write().c_str());
// remove initialCurrencyState when not needed
if (!initialCurrencyState.IsValid())
{
- initialCurrencyState = GetInitialCurrencyState(importCurrencyDef);
+ initialCurrencyState = ConnectedChains.GetCurrencyState(importCurrencyID, importCurrencyDef.startBlock - 1);
}
// either the destination currency must be fractional or the source currency
transferFees.valueMap[systemDestID] += preConversionFee;
newCurrencyConverted = initialCurrencyState.ReserveToNativeRaw(valueOut, initialCurrencyState.conversionPrice[curIdx]);
+ if (newCurrencyConverted == -1)
+ {
+ // if we have an overflow, this isn't going to work
+ newCurrencyConverted = 0;
+ }
if (!carveOutSet)
{
totalCarveOut = importCurrencyDef.GetTotalCarveOut();
carveOutSet = true;
}
- if (totalCarveOut > 0 && totalCarveOut < SATOSHIDEN)
- {
- CAmount newReserveIn = CCurrencyState::NativeToReserveRaw(valueOut, SATOSHIDEN - totalCarveOut);
- totalCarveOuts.valueMap[curTransfer.FirstCurrency()] += valueOut - newReserveIn;
- valueOut = newReserveIn;
- }
- if (curTransfer.FirstCurrency() != systemDestID)
+ if (newCurrencyConverted)
{
- // if this is a fractional currency, everything but fees and carveouts stay in reserve deposit
- // else all that would be reserves is sent to chain ID
- if (!isFractional)
+ if (totalCarveOut > 0 && totalCarveOut < SATOSHIDEN)
{
- AddReserveOutput(curTransfer.FirstCurrency(), valueOut);
- std::vector<CTxDestination> dests({CIdentityID(importCurrencyID)});
- CTokenOutput ro = CTokenOutput(curTransfer.FirstCurrency(), valueOut);
- vOutputs.push_back(CTxOut(0, MakeMofNCCScript(CConditionObj<CTokenOutput>(EVAL_RESERVE_OUTPUT, dests, 1, &ro))));
+ CAmount newReserveIn = CCurrencyState::NativeToReserveRaw(valueOut, SATOSHIDEN - totalCarveOut);
+ totalCarveOuts.valueMap[curTransfer.FirstCurrency()] += valueOut - newReserveIn;
+ valueOut = newReserveIn;
}
- }
- else
- {
- // if it is not fractional, send to currency ID, else leave it in reserve deposit
- if (!isFractional)
+
+ if (curTransfer.FirstCurrency() != systemDestID)
{
- nativeOut += valueOut;
- vOutputs.push_back(CTxOut(valueOut, GetScriptForDestination(CIdentityID(importCurrencyID))));
+ // if this is a fractional currency, everything but fees and carveouts stay in reserve deposit
+ // else all that would be reserves is sent to chain ID
+ if (!isFractional)
+ {
+ AddReserveOutput(curTransfer.FirstCurrency(), valueOut);
+ std::vector<CTxDestination> dests({CIdentityID(importCurrencyID)});
+ CTokenOutput ro = CTokenOutput(curTransfer.FirstCurrency(), valueOut);
+ vOutputs.push_back(CTxOut(0, MakeMofNCCScript(CConditionObj<CTokenOutput>(EVAL_RESERVE_OUTPUT, dests, 1, &ro))));
+ }
+ }
+ else
+ {
+ // if it is not fractional, send to currency ID, else leave it in reserve deposit
+ if (!isFractional)
+ {
+ nativeOut += valueOut;
+ vOutputs.push_back(CTxOut(valueOut, GetScriptForDestination(CIdentityID(importCurrencyID))));
+ }
}
- }
- if (newCurrencyConverted)
- {
preConvertedOutput.valueMap[curTransfer.FirstCurrency()] += newCurrencyConverted;
AddNativeOutConverted(curTransfer.FirstCurrency(), newCurrencyConverted);
AddNativeOutConverted(curTransfer.destCurrencyID, newCurrencyConverted);
AddReserveOutConverted(curTransfer.destCurrencyID, newCurrencyConverted);
AddReserveOutput(curTransfer.destCurrencyID, newCurrencyConverted);
AddReserveInput(curTransfer.destCurrencyID, newCurrencyConverted);
- curTransfer.GetTxOut(CCurrencyValueMap(std::vector<uint160>({curTransfer.destCurrencyID}), std::vector<int64_t>(newCurrencyConverted)),
+ curTransfer.GetTxOut(CCurrencyValueMap(std::vector<uint160>({curTransfer.destCurrencyID}), std::vector<int64_t>({newCurrencyConverted})),
0, newOut);
}
}
}
newCurrencyState.supply += preAllocTotal;
+ newCurrencyState.preConvertedOut = 0;
+ for (auto &oneVal : preConvertedOutput.valueMap)
+ {
+ newCurrencyState.preConvertedOut += oneVal.second;
+ }
if (totalMinted)
{
return flags & FLAG_INITIALLAUNCHIMPORT;
}
+ void SetInitialLaunchImport(bool isInitialLaunchImport=true)
+ {
+ if (isInitialLaunchImport)
+ {
+ flags |= FLAG_INITIALLAUNCHIMPORT;
+ }
+ else
+ {
+ flags &= ~FLAG_INITIALLAUNCHIMPORT;
+ }
+ }
+
UniValue ToUniValue() const;
static std::string CurrencyImportKeyName()
{
public:
CAmount nativeOut; // converted native output, emitted is stored in parent class
+ CAmount preConvertedOut; // how much of the currency out was pre-converted, which is asynchronously added to supply
CAmount nativeFees;
CAmount nativeConversionFees;
std::vector<CAmount> reserveIn; // reserve currency converted to native
std::vector<CAmount> fees; // fee values in native (or reserve if specified) coins for reserve transaction fees for the block
std::vector<CAmount> conversionFees; // total of only conversion fees, which will accrue to the conversion transaction
- CCoinbaseCurrencyState() : nativeOut(0), nativeFees(0), nativeConversionFees(0) {}
+ CCoinbaseCurrencyState() : nativeOut(0), preConvertedOut(0), nativeFees(0), nativeConversionFees(0) {}
CCoinbaseCurrencyState(const CCurrencyState &CurrencyState,
CAmount NativeOut=0, CAmount NativeFees=0, CAmount NativeConversionFees=0,
const std::vector<CAmount> &ConversionPrice=std::vector<CAmount>(),
const std::vector<CAmount> &ViaConversionPrice=std::vector<CAmount>(),
const std::vector<CAmount> &Fees=std::vector<CAmount>(),
- const std::vector<CAmount> &ConversionFees=std::vector<CAmount>()) :
+ const std::vector<CAmount> &ConversionFees=std::vector<CAmount>(),
+ CAmount PreConvertedOut=0) :
CCurrencyState(CurrencyState), nativeOut(NativeOut), nativeFees(NativeFees), nativeConversionFees(NativeConversionFees),
reserveIn(ReserveIn),
nativeIn(NativeIn),
conversionPrice(ConversionPrice),
viaConversionPrice(ViaConversionPrice),
fees(Fees),
- conversionFees(ConversionFees)
+ conversionFees(ConversionFees),
+ preConvertedOut(PreConvertedOut)
{
if (!reserveIn.size()) reserveIn = std::vector<CAmount>(currencies.size());
if (!nativeIn.size()) nativeIn = std::vector<CAmount>(currencies.size());
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(*(CCurrencyState *)this);
READWRITE(nativeOut);
+ READWRITE(preConvertedOut);
READWRITE(nativeFees);
READWRITE(nativeConversionFees);
READWRITE(reserveIn);
{
emitted = 0;
nativeOut = 0;
+ preConvertedOut = 0;
nativeFees = 0;
nativeConversionFees = 0;
reserveIn = std::vector<CAmount>(currencies.size());
reserves[oneCur.second] += (reserveOut[oneCur.second] - reserveIn[oneCur.second]);
supply += nativeIn[oneCur.second];
}
- supply -= (nativeOut + emitted);
+ supply -= ((nativeOut + emitted) - preConvertedOut);
}
CCoinbaseCurrencyState MatchOrders(const std::vector<CReserveTransactionDescriptor> &orders,
reserveIt->second += oneCur.second;
if (reserveIt->second < 0)
{
- printf("CTransaction::GetReserveValueOut(): currency value overflow total: %ld, adding: %ld\n", reserveIt->second, oneCur.second);
- LogPrintf("CTransaction::GetReserveValueOut(): value overflow\n");
+ printf("%s: currency value overflow total: %ld, adding: %ld\n", __func__, reserveIt->second, oneCur.second);
+ LogPrintf("%s: currency value overflow total: %ld, adding: %ld\n", __func__, reserveIt->second, oneCur.second);
return std::map<uint160, CAmount>();
}
}
LOCK2(cs_main, mempool.cs);
- if (!GetAddressIndex(CCrossChainRPCData::GetConditionID(ASSETCHAINS_CHAINID, CReserveTransfer::ReserveTransferKey()),
+ if (!GetAddressIndex(CReserveTransfer::ReserveTransferKey(),
CScript::P2IDX,
addressIndex,
start,
{
CReserveDeposit rd(p.vData[0]);
retVal = rd.reserveValues;
+ retVal.valueMap.erase(ASSETCHAINS_CHAINID);
break;
}
CReserveTransactionDescriptor rtxd(mtx, view, chainActive.Height());
reserveChange = rtxd.ReserveInputMap() - rtxd.ReserveOutputMap();
- //printf("%s: reserve input:\n%s\noutput:\n%s\nchange:\n%s\n", __func__, rtxd.ReserveInputMap().ToUniValue().write(1,2).c_str(), rtxd.ReserveOutputMap().ToUniValue().write(1,2).c_str(), reserveChange.ToUniValue().write(1,2).c_str());
+ printf("%s: reserve input:\n%s\noutput:\n%s\nchange:\n%s\n", __func__, rtxd.ReserveInputMap().ToUniValue().write(1,2).c_str(), rtxd.ReserveOutputMap().ToUniValue().write(1,2).c_str(), reserveChange.ToUniValue().write(1,2).c_str());
bool hasReserveChange = false;
// Valid change
continue;
}
- printf("nTotal: %s\n", nTotal.ToUniValue().write().c_str());
+ //printf("nTotal: %s\n", nTotal.ToUniValue().write().c_str());
CReserveOutSelectionInfo coin(pcoin, i, nAll);
// if our lower total + larger total are not enough, no way we have enough
if ((lowerTotal + largerTotal) < nTotalTarget)
{
- printf("AVAILABLE < nTotalTarget:\nlowerTotal:\n%s\nlargerTotal:\n%s\nnewLargerTotal:\n%s\nTotalTarget:\n%s\n", lowerTotal.ToUniValue().write().c_str(), largerTotal.ToUniValue().write().c_str(), newLargerTotal.ToUniValue().write().c_str(), nTotalTarget.ToUniValue().write().c_str());
+ //printf("AVAILABLE < nTotalTarget:\nlowerTotal:\n%s\nlargerTotal:\n%s\nnewLargerTotal:\n%s\nTotalTarget:\n%s\n", lowerTotal.ToUniValue().write().c_str(), largerTotal.ToUniValue().write().c_str(), newLargerTotal.ToUniValue().write().c_str(), nTotalTarget.ToUniValue().write().c_str());
return false;
}
- printf("\nlowerTotal:\n%s\nlargerTotal:\n%s\nnewLargerTotal:\n%s\nTotalTarget:\n%s\n", lowerTotal.ToUniValue().write().c_str(), largerTotal.ToUniValue().write().c_str(), newLargerTotal.ToUniValue().write().c_str(), nTotalTarget.ToUniValue().write().c_str());
+ //printf("\nlowerTotal:\n%s\nlargerTotal:\n%s\nnewLargerTotal:\n%s\nTotalTarget:\n%s\n", lowerTotal.ToUniValue().write().c_str(), largerTotal.ToUniValue().write().c_str(), newLargerTotal.ToUniValue().write().c_str(), nTotalTarget.ToUniValue().write().c_str());
for (auto &lowerOut : lowerOuts)
{