Skip to content

Commit

Permalink
Change daily LP rewards automatically on subsidy reduction (#390)
Browse files Browse the repository at this point in the history
  • Loading branch information
Bushstar authored May 17, 2021
1 parent 43256b5 commit 4feeddf
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 27 deletions.
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)) {
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 ()

0 comments on commit 4feeddf

Please sign in to comment.