Skip to content

Commit

Permalink
Merge pull request #163 from DeFiCh/v1.4.x
Browse files Browse the repository at this point in the history
Add custom rewards to pool pairs
  • Loading branch information
monstrobishi authored Jan 13, 2021
2 parents 3639d01 + 4ecf5e6 commit a3e61f9
Show file tree
Hide file tree
Showing 13 changed files with 594 additions and 20 deletions.
19 changes: 17 additions & 2 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ class CMainParams : public CChainParams {
consensus.BayfrontHeight = 405000;
consensus.BayfrontMarinaHeight = 465150;
consensus.BayfrontGardensHeight = 488300;
consensus.ClarkeQuayHeight = 595738;

consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
// consensus.pos.nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
Expand Down Expand Up @@ -279,6 +280,7 @@ class CTestNetParams : public CChainParams {
consensus.BayfrontHeight = 3000;
consensus.BayfrontMarinaHeight = 90470;
consensus.BayfrontGardensHeight = 101342;
consensus.ClarkeQuayHeight = 155000;

consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
// consensus.pos.nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
Expand Down Expand Up @@ -415,8 +417,9 @@ class CDevNetParams : public CChainParams {
consensus.BIP66Height = 0;
consensus.AMKHeight = 150;
consensus.BayfrontHeight = 250;
consensus.BayfrontMarinaHeight = 0;
consensus.BayfrontGardensHeight = 0;
consensus.BayfrontMarinaHeight = 300;
consensus.BayfrontGardensHeight = 300;
consensus.ClarkeQuayHeight = 500;

consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.pos.nTargetTimespan = 5 * 60; // 5 min == 10 blocks
Expand Down Expand Up @@ -550,6 +553,7 @@ class CRegTestParams : public CChainParams {
consensus.BayfrontHeight = 10000000;
consensus.BayfrontMarinaHeight = 10000000;
consensus.BayfrontGardensHeight = 10000000;
consensus.ClarkeQuayHeight = 10000000;

consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.pos.nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
Expand Down Expand Up @@ -726,6 +730,17 @@ void CRegTestParams::UpdateActivationParametersFromArgs(const ArgsManager& args)
consensus.BayfrontGardensHeight = static_cast<int>(height);
}

if (gArgs.IsArgSet("-clarkequayheight")) {
int64_t height = gArgs.GetArg("-clarkequayheight", consensus.ClarkeQuayHeight);
if (height < -1 || height >= std::numeric_limits<int>::max()) {
throw std::runtime_error(strprintf("Activation height %ld for ClarkeQuay is out of valid range. Use -1 to disable clarkequay features.", height));
} else if (height == -1) {
LogPrintf("CQ disabled for testing\n");
height = std::numeric_limits<int>::max();
}
consensus.ClarkeQuayHeight = static_cast<int>(height);
}

if (!args.IsArgSet("-vbparams")) return;

for (const std::string& strDeployment : args.GetArgs("-vbparams")) {
Expand Down
2 changes: 2 additions & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ struct Params {
int BayfrontHeight;
int BayfrontMarinaHeight;
int BayfrontGardensHeight;
/** Third major fork. */
int ClarkeQuayHeight;
/** Foundation share after AMK, normalized to COIN = 100% */
CAmount foundationShareDFIP1;

Expand Down
1 change: 1 addition & 0 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ void SetupServerArgs()
gArgs.AddArg("-amkheight", "AMK fork activation height (regtest only)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-bayfrontheight", "Bayfront fork activation height (regtest only)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-bayfrontgardensheight", "Bayfront Gardens fork activation height (regtest only)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-clarkequayheight", "ClarkeQuay fork activation height (regtest only)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
#ifdef USE_UPNP
#if USE_UPNP
gArgs.AddArg("-upnp", "Use UPnP to map the listening port (default: 1 when listening and no -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
Expand Down
105 changes: 103 additions & 2 deletions src/masternodes/mn_checks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1018,9 +1018,16 @@ Res ApplyCreatePoolPairTx(CCustomCSView &mnview, const CCoinsViewCache &coins, c

CPoolPairMessage poolPairMsg;
std::string pairSymbol;
CBalances rewards;
CDataStream ss(metadata, SER_NETWORK, PROTOCOL_VERSION);
ss >> poolPairMsg;
ss >> pairSymbol;

// Read custom pool rewards
if (static_cast<int>(height) >= consensusParams.ClarkeQuayHeight && !ss.empty()) {
ss >> rewards;
}

if (!ss.empty()) {
return Res::Err("%s: deserialization failed: excess %d bytes", base, ss.size());
}
Expand All @@ -1042,12 +1049,12 @@ Res ApplyCreatePoolPairTx(CCustomCSView &mnview, const CCoinsViewCache &coins, c

auto tokenA = mnview.GetToken(poolPairMsg.idTokenA);
if (!tokenA) {
return Res::Err("%s: token %s does not exist!", poolPairMsg.idTokenA.ToString());
return Res::Err("%s: token %s does not exist!", base, poolPairMsg.idTokenA.ToString());
}

auto tokenB = mnview.GetToken(poolPairMsg.idTokenB);
if (!tokenB) {
return Res::Err("%s: token %s does not exist!", poolPairMsg.idTokenB.ToString());
return Res::Err("%s: token %s does not exist!", base, poolPairMsg.idTokenB.ToString());
}

if(pairSymbol.empty())
Expand Down Expand Up @@ -1079,6 +1086,20 @@ Res ApplyCreatePoolPairTx(CCustomCSView &mnview, const CCoinsViewCache &coins, c
rpcInfo->pushKV("tradeable", token.IsTradeable());
rpcInfo->pushKV("finalized", token.IsFinalized());

if (!rewards.balances.empty()) {
UniValue rewardArr(UniValue::VARR);

for (const auto& reward : rewards.balances) {
if (reward.second > 0) {
rewardArr.push_back(CTokenAmount{reward.first, reward.second}.ToString());
}
}

if (!rewardArr.empty()) {
rpcInfo->pushKV("customRewards", rewardArr);
}
}

return Res::Ok(base);
}

Expand All @@ -1098,6 +1119,29 @@ Res ApplyCreatePoolPairTx(CCustomCSView &mnview, const CCoinsViewCache &coins, c
return Res::Err("%s %s: %s", base, pairSymbol, resPP.msg);
}

if (!rewards.balances.empty()) {
// Check tokens exist and remove empty reward amounts
for (auto it = rewards.balances.cbegin(), next_it = it; it != rewards.balances.cend(); it = next_it) {
++next_it;

auto token = pcustomcsview->GetToken(it->first);
if (!token) {
return Res::Err("%s: reward token %d does not exist!", base, it->first.v);
}

if (it->second == 0) {
rewards.balances.erase(it);
}
}

auto resCR = mnview.SetPoolCustomReward(pairToken->first, rewards);

// Will only fail if pool was not actually created in SetPoolPair
if (!resCR.ok) {
return Res::Err("%s %s: %s", base, pairSymbol, resCR.msg);
}
}

return Res::Ok(base);
}

Expand All @@ -1113,11 +1157,18 @@ Res ApplyUpdatePoolPairTx(CCustomCSView & mnview, CCoinsViewCache const & coins,
bool status;
CAmount commission;
CScript ownerAddress;
CBalances rewards;
CDataStream ss(metadata, SER_NETWORK, PROTOCOL_VERSION);
ss >> poolId;
ss >> status;
ss >> commission;
ss >> ownerAddress;

// Read custom pool rewards
if (static_cast<int>(height) >= consensusParams.ClarkeQuayHeight && !ss.empty()) {
ss >> rewards;
}

if (!ss.empty()) {
return Res::Err("Pool Update: deserialization failed: excess %d bytes", ss.size());
}
Expand All @@ -1141,6 +1192,56 @@ Res ApplyUpdatePoolPairTx(CCustomCSView & mnview, CCoinsViewCache const & coins,
rpcInfo->pushKV("commission", ValueFromAmount(commission));
rpcInfo->pushKV("status", status);
rpcInfo->pushKV("ownerAddress", ownerAddress.GetHex());

// Add rewards here before processing them below to avoid adding current rewards
if (!rewards.balances.empty()) {
UniValue rewardArr(UniValue::VARR);

// Check for special case to wipe rewards
if (rewards.balances.size() == 1 && rewards.balances.cbegin()->first == DCT_ID{std::numeric_limits<uint32_t>::max()}
&& rewards.balances.cbegin()->second == std::numeric_limits<CAmount>::max()) {
rpcInfo->pushKV("customRewards", rewardArr);
} else {
for (const auto& reward : rewards.balances) {
if (reward.second > 0) {
rewardArr.push_back(CTokenAmount{reward.first, reward.second}.ToString());
}
}

if (!rewardArr.empty()) {
rpcInfo->pushKV("customRewards", rewardArr);
}
}
}
}

if (!rewards.balances.empty()) {
// Check for special case to wipe rewards
if (rewards.balances.size() == 1 && rewards.balances.cbegin()->first == DCT_ID{std::numeric_limits<uint32_t>::max()}
&& rewards.balances.cbegin()->second == std::numeric_limits<CAmount>::max()) {
rewards.balances.clear();
}

// Check if tokens exist and remove empty reward amounts
for (auto it = rewards.balances.cbegin(), next_it = it; it != rewards.balances.cend(); it = next_it) {
++next_it;

auto token = pcustomcsview->GetToken(it->first);
if (!token) {
return Res::Err("%s: reward token %d does not exist!", base, it->first.v);
}

if (it->second == 0) {
rewards.balances.erase(it);
}
}

auto resCR = mnview.SetPoolCustomReward(poolId, rewards);

// Will only fail if pool was not actually created in SetPoolPair
if (!resCR.ok) {
return Res::Err("%s %s: %s", base, poolId.ToString(), resCR.msg);
}
}

return Res::Ok(base);
Expand Down
64 changes: 58 additions & 6 deletions src/masternodes/mn_rpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1815,6 +1815,31 @@ UniValue poolToJSON(DCT_ID const& id, CPoolPair const& pool, CToken const& token

poolObj.pushKV("rewardPct", ValueFromAmount(pool.rewardPct));

auto rewards = pcustomcsview->GetPoolCustomReward(id);
if (rewards && !rewards->balances.empty()) {
for (auto it = rewards->balances.cbegin(), next_it = it; it != rewards->balances.cend(); it = next_it) {
++next_it;

// Get token balance
const auto balance = pcustomcsview->GetBalance(pool.ownerAddress, it->first).nValue;

// Make there's enough to pay reward otherwise remove it
if (balance < it->second) {
rewards->balances.erase(it);
}
}

if (!rewards->balances.empty()) {
UniValue rewardArr(UniValue::VARR);

for (const auto& reward : rewards->balances) {
rewardArr.push_back(CTokenAmount{reward.first, reward.second}.ToString());
}

poolObj.pushKV("customRewards", rewardArr);
}
}

poolObj.pushKV("creationTx", pool.creationTx.GetHex());
poolObj.pushKV("creationHeight", (uint64_t) pool.creationHeight);
}
Expand Down Expand Up @@ -2500,6 +2525,8 @@ UniValue createpoolpair(const JSONRPCRequest& request) {
"Pool Status: True is Active, False is Restricted"},
{"ownerAddress", RPCArg::Type::STR, RPCArg::Optional::NO,
"Address of the pool owner."},
{"customRewards", RPCArg::Type::STR, RPCArg::Optional::OMITTED,
"Token reward to be paid on each block, multiple can be specified."},
{"pairSymbol", RPCArg::Type::STR, RPCArg::Optional::OMITTED,
"Pair symbol (unique), no longer than " +
std::to_string(CToken::MAX_TOKEN_SYMBOL_LENGTH)},
Expand All @@ -2524,14 +2551,16 @@ UniValue createpoolpair(const JSONRPCRequest& request) {
"\"tokenB\":\"MyToken2\","
"\"commission\":\"0.001\","
"\"status\":\"True\","
"\"ownerAddress\":\"Address\""
"\"ownerAddress\":\"Address\","
"\"customRewards\":\"[\\\"1@tokena\\\",\\\"10@tokenb\\\"]\""
"}' '[{\"txid\":\"id\",\"vout\":0}]'")
+ HelpExampleRpc("createpoolpair", "'{\"tokenA\":\"MyToken1\","
"\"tokenB\":\"MyToken2\","
"\"commission\":\"0.001\","
"\"status\":\"True\","
"\"ownerAddress\":\"Address\""
"}' '[{\"txid\":\"id\",\"vout\":0}]'")
"\"ownerAddress\":\"Address\","
"\"customRewards\":\"[\\\"1@tokena\\\",\\\"10@tokenb\\\"]\""
"}' '[{\"txid\":\"id\",\"vout\":0}]'")
},
}.Check(request);

Expand All @@ -2546,6 +2575,7 @@ UniValue createpoolpair(const JSONRPCRequest& request) {
std::string tokenA, tokenB, pairSymbol;
CAmount commission = 0; // !!!
CScript ownerAddress;
CBalances rewards;
bool status = true; // default Active
UniValue metadataObj = request.params[0].get_obj();
if (!metadataObj["tokenA"].isNull()) {
Expand All @@ -2566,6 +2596,9 @@ UniValue createpoolpair(const JSONRPCRequest& request) {
if (!metadataObj["pairSymbol"].isNull()) {
pairSymbol = metadataObj["pairSymbol"].getValStr();
}
if (!metadataObj["customRewards"].isNull()) {
rewards = DecodeAmounts(pwallet->chain(), metadataObj["customRewards"], "");
}

int targetHeight;
DCT_ID idtokenA, idtokenB;
Expand Down Expand Up @@ -2594,6 +2627,10 @@ UniValue createpoolpair(const JSONRPCRequest& request) {
metadata << static_cast<unsigned char>(CustomTxType::CreatePoolPair)
<< poolPairMsg << pairSymbol;

if (targetHeight >= Params().GetConsensus().ClarkeQuayHeight) {
metadata << rewards;
}

CScript scriptMeta;
scriptMeta << OP_RETURN << ToByteVector(metadata);

Expand Down Expand Up @@ -2648,7 +2685,7 @@ UniValue updatepoolpair(const JSONRPCRequest& request) {
{"status", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Pool Status new property (bool)"},
{"commission", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "Pool commission, up to 10^-8"},
{"ownerAddress", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Address of the pool owner."},

{"customRewards", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Token reward to be paid on each block, multiple can be specified."},
},
},
{"inputs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "A json array of json objects",
Expand All @@ -2668,10 +2705,12 @@ UniValue updatepoolpair(const JSONRPCRequest& request) {
},
RPCExamples{
HelpExampleCli("updatepoolpair", "'{\"pool\":\"POOL\",\"status\":true,"
"\"commission\":0.01,\"ownerAddress\":\"Address\"}' "
"\"commission\":0.01,\"ownerAddress\":\"Address\","
"\"customRewards\":\"[\\\"1@tokena\\\",\\\"10@tokenb\\\"]\"}' "
"'[{\"txid\":\"id\",\"vout\":0}]'")
+ HelpExampleRpc("updatepoolpair", "'{\"pool\":\"POOL\",\"status\":true,"
"\"commission\":0.01,\"ownerAddress\":\"Address\"}' "
"\"commission\":0.01,\"ownerAddress\":\"Address\","
"\"customRewards\":\"[\\\"1@tokena\\\",\\\"10@tokenb\\\"]\"}' "
"'[{\"txid\":\"id\",\"vout\":0}]'")
},
}.Check(request);
Expand All @@ -2688,6 +2727,7 @@ UniValue updatepoolpair(const JSONRPCRequest& request) {
bool status = true;
CAmount commission = -1;
CScript ownerAddress;
CBalances rewards;
UniValue const & metaObj = request.params[0].get_obj();
UniValue const & txInputs = request.params[1];

Expand Down Expand Up @@ -2718,6 +2758,14 @@ UniValue updatepoolpair(const JSONRPCRequest& request) {
if (!metaObj["ownerAddress"].isNull()) {
ownerAddress = DecodeScript(metaObj["ownerAddress"].getValStr());
}
if (!metaObj["customRewards"].isNull()) {
rewards = DecodeAmounts(pwallet->chain(), metaObj["customRewards"], "");

if (rewards.balances.empty()) {
// Add special case to wipe rewards
rewards.balances.insert(std::pair<DCT_ID, CAmount>(DCT_ID{std::numeric_limits<uint32_t>::max()}, std::numeric_limits<CAmount>::max()));
}
}

const auto txVersion = GetTransactionVersion(targetHeight);
CMutableTransaction rawTx(txVersion);
Expand All @@ -2730,6 +2778,10 @@ UniValue updatepoolpair(const JSONRPCRequest& request) {
metadata << static_cast<unsigned char>(CustomTxType::UpdatePoolPair)
<< poolId << status << commission << ownerAddress;

if (targetHeight >= Params().GetConsensus().ClarkeQuayHeight) {
metadata << rewards;
}

CScript scriptMeta;
scriptMeta << OP_RETURN << ToByteVector(metadata);

Expand Down
Loading

0 comments on commit a3e61f9

Please sign in to comment.