Skip to content

Commit 3803cd2

Browse files
Merge pull request #550 from qubic/develop (Release v1.260.0)
Release v1.260.0
2 parents ecc4f9a + 98cbd37 commit 3803cd2

File tree

10 files changed

+451
-102
lines changed

10 files changed

+451
-102
lines changed

src/assets/assets.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -417,8 +417,8 @@ static bool transferShareManagementRights(int sourceOwnershipIndex, int sourcePo
417417
logPM.possessionPublicKey = possessionPublicKey;
418418
logPM.ownershipPublicKey = ownershipPublicKey;
419419
logPM.issuerPublicKey = assets[issuanceIndex].varStruct.issuance.publicKey;
420-
logOM.sourceContractIndex = assets[sourcePossessionIndex].varStruct.ownership.managingContractIndex;
421-
logOM.destinationContractIndex = destinationPossessionManagingContractIndex;
420+
logPM.sourceContractIndex = assets[sourcePossessionIndex].varStruct.ownership.managingContractIndex;
421+
logPM.destinationContractIndex = destinationPossessionManagingContractIndex;
422422
logPM.numberOfShares = numberOfShares;
423423
*((unsigned long long*) & logPM.assetName) = *((unsigned long long*) & assets[assets[sourceOwnershipIndex].varStruct.ownership.issuanceIndex].varStruct.issuance.name); // possible with 7 byte array, because it is followed by memory reserved for terminator byte
424424
logger.logAssetPossessionManagingContractChange(logPM);

src/contract_core/contract_def.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,6 @@ struct __FunctionOrProcedureBeginEndGuard
204204
#define CONTRACT_STATE2_TYPE NOST2
205205
#include "contracts/Nostromo.h"
206206

207-
#ifndef NO_QDRAW
208-
209207
#undef CONTRACT_INDEX
210208
#undef CONTRACT_STATE_TYPE
211209
#undef CONTRACT_STATE2_TYPE
@@ -216,8 +214,6 @@ struct __FunctionOrProcedureBeginEndGuard
216214
#define CONTRACT_STATE2_TYPE QDRAW2
217215
#include "contracts/Qdraw.h"
218216

219-
#endif
220-
221217
// new contracts should be added above this line
222218

223219
#ifdef INCLUDE_CONTRACT_TEST_EXAMPLES
@@ -315,9 +311,7 @@ constexpr struct ContractDescription
315311
{"QBAY", 154, 10000, sizeof(QBAY)}, // proposal in epoch 152, IPO in 153, construction and first use in 154
316312
{"QSWAP", 171, 10000, sizeof(QSWAP)}, // proposal in epoch 169, IPO in 170, construction and first use in 171
317313
{"NOST", 172, 10000, sizeof(NOST)}, // proposal in epoch 170, IPO in 171, construction and first use in 172
318-
#ifndef NO_QDRAW
319314
{"QDRAW", 179, 10000, sizeof(QDRAW)}, // proposal in epoch 177, IPO in 178, construction and first use in 179
320-
#endif
321315
// new contracts should be added above this line
322316
#ifdef INCLUDE_CONTRACT_TEST_EXAMPLES
323317
{"TESTEXA", 138, 10000, sizeof(IPO)},
@@ -421,9 +415,7 @@ static void initializeContracts()
421415
REGISTER_CONTRACT_FUNCTIONS_AND_PROCEDURES(QBAY);
422416
REGISTER_CONTRACT_FUNCTIONS_AND_PROCEDURES(QSWAP);
423417
REGISTER_CONTRACT_FUNCTIONS_AND_PROCEDURES(NOST);
424-
#ifndef NO_QDRAW
425418
REGISTER_CONTRACT_FUNCTIONS_AND_PROCEDURES(QDRAW);
426-
#endif
427419
// new contracts should be added above this line
428420
#ifdef INCLUDE_CONTRACT_TEST_EXAMPLES
429421
REGISTER_CONTRACT_FUNCTIONS_AND_PROCEDURES(TESTEXA);

src/contract_core/ipo.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ static long long bidInContractIPO(long long price, unsigned short quantity, cons
2626
ASSERT(spectrumIndex >= 0);
2727
ASSERT(spectrumIndex == ::spectrumIndex(sourcePublicKey));
2828
ASSERT(contractIndex < contractCount);
29-
ASSERT(system.epoch < contractDescriptions[contractIndex].constructionEpoch);
29+
ASSERT(system.epoch == contractDescriptions[contractIndex].constructionEpoch - 1);
3030

3131
long long registeredBids = -1;
3232

@@ -128,7 +128,7 @@ static void finishIPOs()
128128
{
129129
for (unsigned int contractIndex = 1; contractIndex < contractCount; contractIndex++)
130130
{
131-
if (system.epoch < contractDescriptions[contractIndex].constructionEpoch && contractStates[contractIndex])
131+
if (system.epoch == (contractDescriptions[contractIndex].constructionEpoch - 1) && contractStates[contractIndex])
132132
{
133133
contractStateLock[contractIndex].acquireRead();
134134
IPO* ipo = (IPO*)contractStates[contractIndex];

src/contract_core/qpi_ipo_impl.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ QPI::sint64 QPI::QpiContextProcedureCall::bidInIPO(unsigned int IPOContractIndex
1212
return -1;
1313
}
1414

15-
if (system.epoch >= contractDescriptions[IPOContractIndex].constructionEpoch) // IPO is finished.
15+
if (system.epoch != (contractDescriptions[IPOContractIndex].constructionEpoch - 1)) // IPO has not started yet or is finished.
1616
{
1717
return -1;
1818
}
@@ -30,7 +30,7 @@ QPI::sint64 QPI::QpiContextProcedureCall::bidInIPO(unsigned int IPOContractIndex
3030
// Returns the ID of the entity who has made this IPO bid or NULL_ID if the ipoContractIndex or ipoBidIndex are invalid.
3131
QPI::id QPI::QpiContextFunctionCall::ipoBidId(QPI::uint32 ipoContractIndex, QPI::uint32 ipoBidIndex) const
3232
{
33-
if (ipoContractIndex >= contractCount || system.epoch >= contractDescriptions[ipoContractIndex].constructionEpoch || ipoBidIndex >= NUMBER_OF_COMPUTORS)
33+
if (ipoContractIndex >= contractCount || system.epoch != (contractDescriptions[ipoContractIndex].constructionEpoch - 1) || ipoBidIndex >= NUMBER_OF_COMPUTORS)
3434
{
3535
return NULL_ID;
3636
}
@@ -51,7 +51,7 @@ QPI::sint64 QPI::QpiContextFunctionCall::ipoBidPrice(QPI::uint32 ipoContractInde
5151
return -1;
5252
}
5353

54-
if (system.epoch >= contractDescriptions[ipoContractIndex].constructionEpoch)
54+
if (system.epoch != (contractDescriptions[ipoContractIndex].constructionEpoch - 1))
5555
{
5656
return -2;
5757
}

src/contracts/QUtil.h

Lines changed: 150 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ constexpr uint64 QUTILLogTypeNotAuthorized = 20; // Not autho
5555
constexpr uint64 QUTILLogTypeInsufficientFundsForCancel = 21; // Not have enough funds for poll calcellation
5656
constexpr uint64 QUTILLogTypeMaxPollsReached = 22; // Max epoch per epoch reached
5757

58+
// Fee per shareholder for DistributeQuToShareholders()
59+
constexpr sint64 QUTIL_DISTRIBUTE_QU_TO_SHAREHOLDER_FEE_PER_SHAREHOLDER = 5;
60+
61+
5862
struct QUTILLogger
5963
{
6064
uint32 contractId; // to distinguish bw SCs
@@ -66,6 +70,9 @@ struct QUTILLogger
6670
// Other data go here
6771
sint8 _terminator; // Only data before "_terminator" are logged
6872
};
73+
74+
// Deactivate logger for delay function
75+
#if 0
6976
struct QUTILDFLogger
7077
{
7178
uint32 contractId; // to distinguish bw SCs
@@ -76,6 +83,7 @@ struct QUTILDFLogger
7683
id result;
7784
sint8 _terminator; // Only data before "_terminator" are logged
7885
};
86+
#endif
7987

8088
// poll and voter structs
8189
struct QUTILPoll {
@@ -223,6 +231,7 @@ struct QUTIL : public ContractBase
223231
id currentId;
224232
sint64 t;
225233
uint64 useNext;
234+
uint64 totalNumTransfers;
226235
QUTILLogger logger;
227236
};
228237

@@ -492,9 +501,33 @@ struct QUTIL : public ContractBase
492501
{
493502
locals.logger = QUTILLogger{ 0, 0, qpi.invocator(), SELF, qpi.invocationReward(), QUTIL_STM1_TRIGGERED };
494503
LOG_INFO(locals.logger);
495-
state.total = input.amt0 + input.amt1 + input.amt2 + input.amt3 + input.amt4 + input.amt5 + input.amt6 + input.amt7 + input.amt8 + input.amt9 + input.amt10 + input.amt11 + input.amt12 + input.amt13 + input.amt14 + input.amt15 + input.amt16 + input.amt17 + input.amt18 + input.amt19 + input.amt20 + input.amt21 + input.amt22 + input.amt23 + input.amt24 + QUTIL_STM1_INVOCATION_FEE;
496-
// invalid amount (<0), return fund and exit
497-
if ((input.amt0 < 0) || (input.amt1 < 0) || (input.amt2 < 0) || (input.amt3 < 0) || (input.amt4 < 0) || (input.amt5 < 0) || (input.amt6 < 0) || (input.amt7 < 0) || (input.amt8 < 0) || (input.amt9 < 0) || (input.amt10 < 0) || (input.amt11 < 0) || (input.amt12 < 0) || (input.amt13 < 0) || (input.amt14 < 0) || (input.amt15 < 0) || (input.amt16 < 0) || (input.amt17 < 0) || (input.amt18 < 0) || (input.amt19 < 0) || (input.amt20 < 0) || (input.amt21 < 0) || (input.amt22 < 0) || (input.amt23 < 0) || (input.amt24 < 0))
504+
505+
// invalid amount (<0 or >= MAX_AMOUNT), return fund and exit
506+
if ((input.amt0 < 0) || (input.amt0 >= MAX_AMOUNT)
507+
|| (input.amt1 < 0) || (input.amt1 >= MAX_AMOUNT)
508+
|| (input.amt2 < 0) || (input.amt2 >= MAX_AMOUNT)
509+
|| (input.amt3 < 0) || (input.amt3 >= MAX_AMOUNT)
510+
|| (input.amt4 < 0) || (input.amt4 >= MAX_AMOUNT)
511+
|| (input.amt5 < 0) || (input.amt5 >= MAX_AMOUNT)
512+
|| (input.amt6 < 0) || (input.amt6 >= MAX_AMOUNT)
513+
|| (input.amt7 < 0) || (input.amt7 >= MAX_AMOUNT)
514+
|| (input.amt8 < 0) || (input.amt8 >= MAX_AMOUNT)
515+
|| (input.amt9 < 0) || (input.amt9 >= MAX_AMOUNT)
516+
|| (input.amt10 < 0) || (input.amt10 >= MAX_AMOUNT)
517+
|| (input.amt11 < 0) || (input.amt11 >= MAX_AMOUNT)
518+
|| (input.amt12 < 0) || (input.amt12 >= MAX_AMOUNT)
519+
|| (input.amt13 < 0) || (input.amt13 >= MAX_AMOUNT)
520+
|| (input.amt14 < 0) || (input.amt14 >= MAX_AMOUNT)
521+
|| (input.amt15 < 0) || (input.amt15 >= MAX_AMOUNT)
522+
|| (input.amt16 < 0) || (input.amt16 >= MAX_AMOUNT)
523+
|| (input.amt17 < 0) || (input.amt17 >= MAX_AMOUNT)
524+
|| (input.amt18 < 0) || (input.amt18 >= MAX_AMOUNT)
525+
|| (input.amt19 < 0) || (input.amt19 >= MAX_AMOUNT)
526+
|| (input.amt20 < 0) || (input.amt20 >= MAX_AMOUNT)
527+
|| (input.amt21 < 0) || (input.amt21 >= MAX_AMOUNT)
528+
|| (input.amt22 < 0) || (input.amt22 >= MAX_AMOUNT)
529+
|| (input.amt23 < 0) || (input.amt23 >= MAX_AMOUNT)
530+
|| (input.amt24 < 0) || (input.amt24 >= MAX_AMOUNT))
498531
{
499532
locals.logger = QUTILLogger{ 0, 0, qpi.invocator(), SELF, qpi.invocationReward(), QUTIL_STM1_INVALID_AMOUNT_NUMBER };
500533
output.returnCode = QUTIL_STM1_INVALID_AMOUNT_NUMBER;
@@ -504,9 +537,40 @@ struct QUTIL : public ContractBase
504537
qpi.transfer(qpi.invocator(), qpi.invocationReward());
505538
}
506539
}
540+
541+
// Make sure that the sum of all amounts does not overflow and is equal to qpi.invocationReward()
542+
state.total = qpi.invocationReward();
543+
state.total -= input.amt0; if (state.total < 0) goto exit;
544+
state.total -= input.amt1; if (state.total < 0) goto exit;
545+
state.total -= input.amt2; if (state.total < 0) goto exit;
546+
state.total -= input.amt3; if (state.total < 0) goto exit;
547+
state.total -= input.amt4; if (state.total < 0) goto exit;
548+
state.total -= input.amt5; if (state.total < 0) goto exit;
549+
state.total -= input.amt6; if (state.total < 0) goto exit;
550+
state.total -= input.amt7; if (state.total < 0) goto exit;
551+
state.total -= input.amt8; if (state.total < 0) goto exit;
552+
state.total -= input.amt9; if (state.total < 0) goto exit;
553+
state.total -= input.amt10; if (state.total < 0) goto exit;
554+
state.total -= input.amt11; if (state.total < 0) goto exit;
555+
state.total -= input.amt12; if (state.total < 0) goto exit;
556+
state.total -= input.amt13; if (state.total < 0) goto exit;
557+
state.total -= input.amt14; if (state.total < 0) goto exit;
558+
state.total -= input.amt15; if (state.total < 0) goto exit;
559+
state.total -= input.amt16; if (state.total < 0) goto exit;
560+
state.total -= input.amt17; if (state.total < 0) goto exit;
561+
state.total -= input.amt18; if (state.total < 0) goto exit;
562+
state.total -= input.amt19; if (state.total < 0) goto exit;
563+
state.total -= input.amt20; if (state.total < 0) goto exit;
564+
state.total -= input.amt21; if (state.total < 0) goto exit;
565+
state.total -= input.amt22; if (state.total < 0) goto exit;
566+
state.total -= input.amt23; if (state.total < 0) goto exit;
567+
state.total -= input.amt24; if (state.total < 0) goto exit;
568+
state.total -= QUTIL_STM1_INVOCATION_FEE; if (state.total < 0) goto exit;
569+
507570
// insufficient or too many qubic transferred, return fund and exit (we don't want to return change)
508-
if (qpi.invocationReward() != state.total)
571+
if (state.total != 0)
509572
{
573+
exit:
510574
locals.logger = QUTILLogger{ 0, 0, qpi.invocator(), SELF, qpi.invocationReward(), QUTIL_STM1_WRONG_FUND };
511575
LOG_INFO(locals.logger);
512576
output.returnCode = QUTIL_STM1_WRONG_FUND;
@@ -667,7 +731,7 @@ struct QUTIL : public ContractBase
667731
LOG_INFO(locals.logger);
668732
qpi.transfer(input.dst24, input.amt24);
669733
}
670-
locals.logger = QUTILLogger{ 0, 0, qpi.invocator(), SELF, state.total, QUTIL_STM1_SUCCESS };
734+
locals.logger = QUTILLogger{ 0, 0, qpi.invocator(), SELF, qpi.invocationReward(), QUTIL_STM1_SUCCESS};
671735
LOG_INFO(locals.logger);
672736
output.returnCode = QUTIL_STM1_SUCCESS;
673737
qpi.burn(QUTIL_STM1_INVOCATION_FEE);
@@ -687,7 +751,8 @@ struct QUTIL : public ContractBase
687751
output.total = 0;
688752

689753
// Number of addresses and transfers is > 0 and total transfers do not exceed limit (including 2 transfers from invocator to contract and contract to invocator)
690-
if (input.dstCount <= 0 || input.numTransfersEach <= 0 || input.dstCount * input.numTransfersEach + 2 > CONTRACT_ACTION_TRACKER_SIZE)
754+
locals.totalNumTransfers = smul((uint64)input.dstCount, (uint64)input.numTransfersEach);
755+
if (input.dstCount <= 0 || input.numTransfersEach <= 0 || locals.totalNumTransfers > CONTRACT_ACTION_TRACKER_SIZE - 2)
691756
{
692757
if (qpi.invocationReward() > 0)
693758
{
@@ -700,7 +765,7 @@ struct QUTIL : public ContractBase
700765
}
701766

702767
// Check the fund is enough
703-
if (qpi.invocationReward() < input.dstCount * input.numTransfersEach)
768+
if ((uint64)qpi.invocationReward() < locals.totalNumTransfers)
704769
{
705770
if (qpi.invocationReward() > 0)
706771
{
@@ -1181,6 +1246,8 @@ struct QUTIL : public ContractBase
11811246
state.dfMiningSeed = qpi.getPrevSpectrumDigest();
11821247
}
11831248

1249+
// Deactivate delay function
1250+
#if 0
11841251
struct BEGIN_TICK_locals
11851252
{
11861253
m256i dfPubkey, dfNonce;
@@ -1194,10 +1261,11 @@ struct QUTIL : public ContractBase
11941261
locals.dfPubkey = qpi.getPrevSpectrumDigest();
11951262
locals.dfNonce = qpi.getPrevComputerDigest();
11961263
state.dfCurrentState = qpi.computeMiningFunction(state.dfMiningSeed, locals.dfPubkey, locals.dfNonce);
1197-
1264+
11981265
locals.logger = QUTILDFLogger{ 0, 0, locals.dfNonce, locals.dfPubkey, state.dfMiningSeed, state.dfCurrentState};
11991266
LOG_INFO(locals.logger);
12001267
}
1268+
#endif
12011269

12021270
/*
12031271
* @return Return total number of shares that currently exist of the asset given as input
@@ -1207,6 +1275,79 @@ struct QUTIL : public ContractBase
12071275
output = qpi.numberOfShares(input);
12081276
}
12091277

1278+
struct DistributeQuToShareholders_input
1279+
{
1280+
Asset asset;
1281+
};
1282+
struct DistributeQuToShareholders_output
1283+
{
1284+
sint64 shareholders;
1285+
sint64 totalShares;
1286+
sint64 amountPerShare;
1287+
sint64 fees;
1288+
};
1289+
struct DistributeQuToShareholders_locals
1290+
{
1291+
AssetPossessionIterator iter;
1292+
sint64 payBack;
1293+
};
1294+
1295+
PUBLIC_PROCEDURE_WITH_LOCALS(DistributeQuToShareholders)
1296+
{
1297+
// 1. Compute fee (increases linear with number of shareholders)
1298+
// 1.1. Count shareholders and shares
1299+
for (locals.iter.begin(input.asset); !locals.iter.reachedEnd(); locals.iter.next())
1300+
{
1301+
if (locals.iter.numberOfPossessedShares() > 0)
1302+
{
1303+
++output.shareholders;
1304+
output.totalShares += locals.iter.numberOfPossessedShares();
1305+
}
1306+
}
1307+
1308+
// 1.2. Cancel if there are no shareholders
1309+
if (output.shareholders == 0)
1310+
{
1311+
qpi.transfer(qpi.invocator(), qpi.invocationReward());
1312+
return;
1313+
}
1314+
1315+
// 1.3. Compute fee (proportional to number of shareholders)
1316+
output.fees = output.shareholders * QUTIL_DISTRIBUTE_QU_TO_SHAREHOLDER_FEE_PER_SHAREHOLDER;
1317+
1318+
// 1.4. Compute QU per share
1319+
output.amountPerShare = div<sint64>(qpi.invocationReward() - output.fees, output.totalShares);
1320+
1321+
// 1.5. Cancel if amount is not sufficient to pay fees and at least one QU per share
1322+
if (output.amountPerShare <= 0)
1323+
{
1324+
qpi.transfer(qpi.invocator(), qpi.invocationReward());
1325+
return;
1326+
}
1327+
1328+
// 1.6. compute payback QU (remainder of distribution)
1329+
locals.payBack = qpi.invocationReward() - output.totalShares * output.amountPerShare - output.fees;
1330+
ASSERT(locals.payBack >= 0);
1331+
1332+
// 2. Distribute to shareholders
1333+
for (locals.iter.begin(input.asset); !locals.iter.reachedEnd(); locals.iter.next())
1334+
{
1335+
if (locals.iter.numberOfPossessedShares() > 0)
1336+
{
1337+
qpi.transfer(locals.iter.possessor(), locals.iter.numberOfPossessedShares() * output.amountPerShare);
1338+
}
1339+
}
1340+
1341+
// 3. Burn fee
1342+
qpi.burn(output.fees);
1343+
1344+
// 4. pay back QU that cannot be evenly distributed
1345+
if (locals.payBack > 0)
1346+
{
1347+
qpi.transfer(qpi.invocator(), locals.payBack);
1348+
}
1349+
}
1350+
12101351
REGISTER_USER_FUNCTIONS_AND_PROCEDURES()
12111352
{
12121353
REGISTER_USER_FUNCTION(GetSendToManyV1Fee, 1);
@@ -1222,5 +1363,6 @@ struct QUTIL : public ContractBase
12221363
REGISTER_USER_PROCEDURE(CreatePoll, 4);
12231364
REGISTER_USER_PROCEDURE(Vote, 5);
12241365
REGISTER_USER_PROCEDURE(CancelPoll, 6);
1366+
REGISTER_USER_PROCEDURE(DistributeQuToShareholders, 7);
12251367
}
12261368
};

0 commit comments

Comments
 (0)