Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change daily LP rewards automatically on subsidy reduction #390

Merged
merged 1 commit into from
May 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@ void SetupServerArgs()
gArgs.AddArg("-masternode_operator=<address>", "Masternode operator address (default: empty)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-dummypos", "Flag to skip PoS-related checks (regtest only)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-txnotokens", "Flag to force old tx serialization (regtest only)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-subsidytest", "Flag to enable new subsidy rules (regtest only)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-anchorquorum", "Min quorum size (regtest only)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-spv", "Enable SPV to bitcoin blockchain (default: 1)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-criminals", "punishment of criminal nodes (default: 0, regtest only)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
Expand Down
6 changes: 5 additions & 1 deletion src/masternodes/govvariables/lp_daily_dfi_reward.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ UniValue LP_DAILY_DFI_REWARD::Export() const {
return ValueFromAmount(dailyReward);
}

Res LP_DAILY_DFI_REWARD::Validate(const CCustomCSView &) const
Res LP_DAILY_DFI_REWARD::Validate(const CCustomCSView & view) const
{
if (view.GetLastHeight() >= static_cast<uint32_t>(Params().GetConsensus().EunosHeight)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We set last height just before ConnectBlock ends, so in Eunos height GetLastHeight will point to previous one, do you think? It can be used by -1 at end.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An off by one in this circumstance does not make a difference, we do not expect to set LP_DAILY_DFI_REWARD manually and especially not on the hard fork block. The automatic changing of the LP_DAILY_DFI_REWARD comes after parsing of the setgov custom TX.

return Res::Err("Cannot be set manually after Eunos hard fork");
}

// nothing to do
return Res::Ok();
}
Expand Down
39 changes: 36 additions & 3 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1131,14 +1131,15 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
{
CAmount nSubsidy = consensusParams.baseBlockSubsidy;

if (Params().NetworkIDString() != CBaseChainParams::REGTEST || consensusParams.EunosHeight == 1)
if (Params().NetworkIDString() != CBaseChainParams::REGTEST ||
(Params().NetworkIDString() == CBaseChainParams::REGTEST && gArgs.GetBoolArg("-subsidytest", false)))
{
if (nHeight >= consensusParams.EunosHeight)
{
nSubsidy = consensusParams.newBaseBlockSubsidy;
const size_t reductions = (nHeight - consensusParams.EunosHeight) / consensusParams.emissionReductionPeriod;

// See if we already have thie reduction calculated and return if found.
// See if we already have this reduction calculated and return if found.
if (subsidyReductions.find(reductions) != subsidyReductions.end())
{
return subsidyReductions[reductions];
Expand Down Expand Up @@ -2085,7 +2086,18 @@ void ReverseGeneralCoinbaseTx(CCustomCSView & mnview, int height)
for (const auto& kv : Params().GetConsensus().newNonUTXOSubsidies)
{
CAmount subsidy = CalculateCoinbaseReward(blockReward, kv.second);
mnview.SubCommunityBalance(kv.first, subsidy);

// Remove Swap, Futures and Options balances from Unallocated
if (kv.first == CommunityAccountType::Swap ||
kv.first == CommunityAccountType::Futures ||
kv.first == CommunityAccountType::Options)
{
mnview.SubCommunityBalance(CommunityAccountType::Unallocated, subsidy);
}
else
{
mnview.SubCommunityBalance(kv.first, subsidy);
}
}
}
else
Expand Down Expand Up @@ -2571,6 +2583,27 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
// make all changes to the new cache/snapshot to make it possible to take a diff later:
CCustomCSView cache(mnview);

// Hard coded LP_DAILY_DFI_REWARD change
if (pindex->nHeight >= chainparams.GetConsensus().EunosHeight)
{
const auto& incentivePair = chainparams.GetConsensus().newNonUTXOSubsidies.find(CommunityAccountType::IncentiveFunding);
if (incentivePair != chainparams.GetConsensus().newNonUTXOSubsidies.end())
{
CAmount subsidy = CalculateCoinbaseReward(GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()), incentivePair->second);
// Change daily LP reward if it has changed
auto var = cache.GetVariable(LP_DAILY_DFI_REWARD::TypeName());
if (var) {
// Cast to avoid UniValue in GovVariable Export/Import
auto lpVar = dynamic_cast<LP_DAILY_DFI_REWARD*>(var.get());
if (lpVar && lpVar->dailyReward != subsidy) {
lpVar->dailyReward = subsidy;
lpVar->Apply(cache, pindex->nHeight);
cache.SetVariable(*lpVar);
}
}
}
}

// hardfork commissions update
CAmount distributed = cache.UpdatePoolRewards(
[&](CScript const & owner, DCT_ID tokenID) {
Expand Down
8 changes: 3 additions & 5 deletions test/functional/feature_burn_address.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,8 @@ def run_test(self):
assert_equal(result[0]['type'], 'AccountToAccount')
assert_equal(result[0]['amounts'][0], '1.00000000@DFI')

# Auto auth from failed accounttoaccount
assert_equal(result[1]['owner'], 'mfburnZSAM7Gs1hpDeNaMotJXSGA7edosG')
assert_equal(result[1]['type'], 'None')
assert_equal(result[1]['amounts'][0], '0.99988640@DFI')
# Auto auth burnt amount
auth_burn_amount = result[1]['amounts'][0][0:10]

# Send to burn address with accounttoutxos
self.nodes[0].accounttoutxos(funded_address, {burn_address:"2@0"})
Expand Down Expand Up @@ -150,7 +148,7 @@ def run_test(self):
# Test output of getburninfo
result = self.nodes[0].getburninfo()
assert_equal(result['address'], burn_address)
assert_equal(result['amount'], Decimal('12.99988640'))
assert_equal(result['amount'], Decimal('12.00000000') + Decimal(auth_burn_amount))
assert_equal(result['tokens'][0], '1.00000000@DFI')
assert_equal(result['tokens'][1], '100.00000000@GOLD#128')
assert_equal(result['feeburn'], Decimal('2.00000000'))
Expand Down
32 changes: 30 additions & 2 deletions test/functional/feature_dfip8_communitybalances.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ class Dfip8Test(DefiTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
self.extra_args = [['-txnotokens=0', '-amkheight=1', '-eunosheight=1']]
self.extra_args = [['-txnotokens=0', '-amkheight=1', '-eunosheight=1', '-subsidytest=1']]

def run_test(self):

self.nodes[0].generate(1)

result = self.nodes[0].listcommunitybalances()
Expand Down Expand Up @@ -76,6 +75,35 @@ def run_test(self):
assert_equal(getblock['nonutxo'][0]['IncentiveFunding'], Decimal('101.37356916'))
assert_equal(getblock['nonutxo'][0]['Burnt'], Decimal('144.55193810'))

# Invalidate a block and test rollback
self.nodes[0].invalidateblock(self.nodes[0].getblockhash(self.nodes[0].getblockcount()))
result = self.nodes[0].listcommunitybalances()

assert_equal(result['AnchorReward'], Decimal('12.23086488'))
assert_equal(result['IncentiveFunding'], Decimal('15563.77556916'))
assert_equal(result['Burnt'], Decimal('22192.90433810'))

getblock = self.nodes[0].getblock(self.nodes[0].getblockhash(self.nodes[0].getblockcount()))

assert_equal(getblock['nonutxo'][0]['AnchorReward'], Decimal('0.07966488'))
assert_equal(getblock['nonutxo'][0]['IncentiveFunding'], Decimal('101.37356916'))
assert_equal(getblock['nonutxo'][0]['Burnt'], Decimal('144.55193810'))

#Go forward again to first reduction
self.nodes[0].generate(1)

result = self.nodes[0].listcommunitybalances()

assert_equal(result['AnchorReward'], Decimal('12.31052976'))
assert_equal(result['IncentiveFunding'], Decimal('15665.14913832'))
assert_equal(result['Burnt'], Decimal('22337.45627620'))

getblock = self.nodes[0].getblock(self.nodes[0].getblockhash(self.nodes[0].getblockcount()))

assert_equal(getblock['nonutxo'][0]['AnchorReward'], Decimal('0.07966488'))
assert_equal(getblock['nonutxo'][0]['IncentiveFunding'], Decimal('101.37356916'))
assert_equal(getblock['nonutxo'][0]['Burnt'], Decimal('144.55193810'))

# Ten reductions plus one
self.nodes[0].generate(1502 - self.nodes[0].getblockcount())

Expand Down
28 changes: 20 additions & 8 deletions test/functional/feature_poolswap_mechanism.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ def set_test_params(self):
# node2: revert create (all)
self.setup_clean_chain = True
self.extra_args = [
['-txnotokens=0', '-amkheight=0', '-bayfrontheight=0', '-bayfrontgardensheight=0', '-eunosheight=120'],
['-txnotokens=0', '-amkheight=0', '-bayfrontheight=0', '-bayfrontgardensheight=0', '-eunosheight=120'],
['-txnotokens=0', '-amkheight=0', '-bayfrontheight=0', '-bayfrontgardensheight=0', '-eunosheight=120']
['-txnotokens=0', '-amkheight=0', '-bayfrontheight=0', '-bayfrontgardensheight=0', '-eunosheight=120', '-subsidytest=1'],
['-txnotokens=0', '-amkheight=0', '-bayfrontheight=0', '-bayfrontgardensheight=0', '-eunosheight=120', '-subsidytest=1'],
['-txnotokens=0', '-amkheight=0', '-bayfrontheight=0', '-bayfrontgardensheight=0', '-eunosheight=120', '-subsidytest=1']
]

# SET parameters for create tokens and pools
Expand Down Expand Up @@ -71,6 +71,7 @@ def create_token(self, symbol, address):
"collateralAddress": address
}, [])
self.nodes[0].generate(1)
self.sync_blocks()
self.tokens.append(symbol)

def create_pool(self, tokenA, tokenB, owner):
Expand All @@ -82,6 +83,7 @@ def create_pool(self, tokenA, tokenB, owner):
"ownerAddress": owner
}, []))
self.nodes[0].generate(1)
self.sync_blocks()

def create_pools(self, owner):
for i in range(self.COUNT_POOLS):
Expand All @@ -100,6 +102,7 @@ def mint_tokens(self, owner):
self.nodes[0].generate(1)
self.nodes[0].minttokens(mint_amount + "@" + self.get_id_token(item), [])
self.nodes[0].generate(1)
self.sync_blocks()
return mint_amount

def send_tokens(self, owner):
Expand All @@ -117,6 +120,7 @@ def send_tokens(self, owner):
self.nodes[0].generate(1)
self.nodes[0].accounttoaccount(owner, outputs, [])
self.nodes[0].generate(1)
self.sync_blocks()

def add_pools_liquidity(self, owner):
for item in range(self.COUNT_POOLS):
Expand All @@ -143,6 +147,7 @@ def add_pools_liquidity(self, owner):
self.accounts[idx]: [amountA, amountB]
}, self.accounts[idx], [])
self.nodes[0].generate(1)
self.sync_blocks()

def slope_swap(self, unswapped, poolFrom, poolTo):
swapped = poolTo - (poolTo * poolFrom / (poolFrom + unswapped))
Expand All @@ -151,7 +156,7 @@ def slope_swap(self, unswapped, poolFrom, poolTo):

return (poolFrom, poolTo)

def poolswap(self):
def poolswap(self, nodes):
for item in range(self.COUNT_POOLS):
tokenA = "GOLD" + str(item)
tokenB = "SILVER" + str(item)
Expand All @@ -165,6 +170,7 @@ def poolswap(self):
for idx in range(start, end):
self.nodes[0].sendmany("", { self.accounts[idx] : 0.02 })
self.nodes[0].generate(1)
self.sync_blocks(nodes)

amount = random.randint(1, self.AMOUNT_TOKEN // 2)
amountsB = {}
Expand All @@ -187,6 +193,7 @@ def poolswap(self):
"tokenTo": str(self.get_id_token(tokenA)),
}, [])
self.nodes[0].generate(1)
self.sync_blocks(nodes)

for idx in range(start, end):
liquidity = self.nodes[0].getaccount(self.accounts[idx], {}, True)[idPool]
Expand Down Expand Up @@ -222,10 +229,9 @@ def run_test(self):
print("Generating initial chain...")

self.nodes[0].generate(100)
self.sync_all()

owner = self.nodes[0].getnewaddress("", "legacy")
self.nodes[0].generate(1)
self.sync_blocks()

# START
#========================
Expand Down Expand Up @@ -280,6 +286,7 @@ def run_test(self):
self.nodes[0].setgov({ "LP_SPLITS": obj })
self.nodes[0].setgov({ "LP_DAILY_DFI_REWARD": self.LP_DAILY_DFI_REWARD })
self.nodes[0].generate(1)
self.sync_blocks()

g1 = self.nodes[0].getgov("LP_SPLITS")
for i in range(self.COUNT_POOLS):
Expand All @@ -294,7 +301,8 @@ def run_test(self):

print("Swapping tokens...")
start_time = time.time()
self.poolswap()
nodes = self.nodes[0:2]
self.poolswap(nodes)
end_time = time.time() - start_time
print("Tokens exchanged")
print("Elapsed time: {} s".format(end_time))
Expand All @@ -309,8 +317,12 @@ def run_test(self):
self.sync_blocks()

assert(self.nodes[0].getblockcount() == 120) # eunos

self.LP_DAILY_DFI_REWARD = self.nodes[0].getgov("LP_DAILY_DFI_REWARD")['LP_DAILY_DFI_REWARD']
assert_equal(self.LP_DAILY_DFI_REWARD, Decimal('103.08268000'))

print("Swapping tokens after eunos height...")
self.poolswap()
self.poolswap(self.nodes)


if __name__ == '__main__':
Expand Down
40 changes: 32 additions & 8 deletions test/functional/feature_setgov.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from test_framework.authproxy import JSONRPCException
from test_framework.util import \
connect_nodes, disconnect_nodes
connect_nodes, disconnect_nodes, assert_equal
from decimal import Decimal


Expand All @@ -21,16 +21,11 @@ def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
self.extra_args = [
['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50'],
['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50']]
['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50', '-eunosheight=200', '-subsidytest=1'],
['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50', '-eunosheight=200', '-subsidytest=1']]


def run_test(self):
# fast check for debug
print (self.nodes[0].getgov("LP_SPLITS"))
print (self.nodes[0].getgov("LP_DAILY_DFI_REWARD"))
# return

print("Generating initial chain...")
self.setup_tokens()

Expand Down Expand Up @@ -200,6 +195,35 @@ def run_test(self):
and pool2['rewardPct'] == Decimal('0.40000000')
and pool3['rewardPct'] == Decimal('0.10000000'))

# Generate to Eunos hard fork
self.nodes[0].clearmempool()
self.nodes[0].generate(200 - self.nodes[0].getblockcount())

# Try and set LP_DAILY_DFI_REWARD manually
try:
self.nodes[0].setgov({ "LP_DAILY_DFI_REWARD": 100})
except JSONRPCException as e:
errorString = e.error['message']
assert("Cannot be set manually after Eunos hard fork" in errorString)

# Check new subsidy
assert_equal(self.nodes[0].getgov('LP_DAILY_DFI_REWARD')['LP_DAILY_DFI_REWARD'], Decimal('103.08268000'))

# Roll back
self.nodes[0].invalidateblock(self.nodes[0].getblockhash(self.nodes[0].getblockcount()))

# Check subsidy restored
assert_equal(self.nodes[0].getgov('LP_DAILY_DFI_REWARD')['LP_DAILY_DFI_REWARD'], Decimal('35.50000000'))

# Move to second reduction and check reward
self.nodes[0].generate(151)
assert_equal(self.nodes[0].getgov('LP_DAILY_DFI_REWARD')['LP_DAILY_DFI_REWARD'], Decimal('101.37356916'))

# Rollback from second reduction
self.nodes[0].invalidateblock(self.nodes[0].getblockhash(self.nodes[0].getblockcount()))

# Check subsidy restored
assert_equal(self.nodes[0].getgov('LP_DAILY_DFI_REWARD')['LP_DAILY_DFI_REWARD'], Decimal('103.08268000'))

if __name__ == '__main__':
GovsetTest ().main ()