def test_staker_collects_staking_reward(testerchain, test_registry, staker, blockchain_ursulas, agency, token_economics, ursula_decentralized_test_config): token_agent = ContractAgency.get_agent(NucypherTokenAgent, registry=test_registry) tpower = TransactingPower(account=testerchain.etherbase_account, signer=Web3Signer(testerchain.client)) # Give more tokens to staker token_airdrop(token_agent=token_agent, transacting_power=tpower, addresses=[staker.checksum_address], amount=DEVELOPMENT_TOKEN_AIRDROP_AMOUNT) staker.initialize_stake( amount=NU(token_economics.minimum_allowed_locked, 'NuNit'), # Lock the minimum amount of tokens lock_periods=int(token_economics.minimum_locked_periods) ) # ... for the fewest number of periods # Get an unused address for a new worker worker_address = testerchain.unassigned_accounts[-1] staker.bond_worker(worker_address=worker_address) # Create this worker and bond it with the staker ursula = make_decentralized_ursulas( ursula_config=ursula_decentralized_test_config, stakers_addresses=[staker.checksum_address], workers_addresses=[worker_address], registry=test_registry, commit_now=False).pop() # ...mint few tokens... for _ in range(2): ursula.commit_to_next_period() testerchain.time_travel(periods=1) # Check mintable periods assert staker.mintable_periods() == 1 ursula.commit_to_next_period() # ...wait more... assert staker.mintable_periods() == 0 testerchain.time_travel(periods=2) assert staker.mintable_periods() == 2 # Capture the current token balance of the staker initial_balance = staker.token_balance assert token_agent.get_balance(staker.checksum_address) == initial_balance # Profit! staked = staker.non_withdrawable_stake() owned = staker.owned_tokens() staker.collect_staking_reward() assert staker.owned_tokens() == staked final_balance = staker.token_balance assert final_balance == initial_balance + owned - staked
def test_stake_in_idle_network(testerchain, token_economics, test_registry): # Let's fund a staker first token_agent = NucypherTokenAgent(registry=test_registry) token_airdrop(origin=testerchain.etherbase_account, addresses=testerchain.stakers_accounts, token_agent=token_agent, amount=DEVELOPMENT_TOKEN_AIRDROP_AMOUNT) account = testerchain.stakers_accounts[0] staker = Staker(is_me=True, checksum_address=account, registry=test_registry) # Mock TransactingPower consumption staker.transacting_power = TransactingPower( password=INSECURE_DEVELOPMENT_PASSWORD, account=staker.checksum_address) staker.transacting_power.activate() # Since StakingEscrow hasn't been activated yet, deposit should work but making a commitment must fail amount = token_economics.minimum_allowed_locked periods = token_economics.minimum_locked_periods staker.initialize_stake(amount=amount, lock_periods=periods) staker.bond_worker(account) with pytest.raises((TransactionFailed, ValueError)): staker.staking_agent.commit_to_next_period(worker_address=account)
def test_stake_in_idle_network(testerchain, token_economics, test_registry): # Let's fund a staker first token_agent = NucypherTokenAgent(registry=test_registry) tpower = TransactingPower(account=testerchain.etherbase_account, signer=Web3Signer(testerchain.client)) token_airdrop(transacting_power=tpower, addresses=testerchain.stakers_accounts, token_agent=token_agent, amount=DEVELOPMENT_TOKEN_AIRDROP_AMOUNT) account = testerchain.stakers_accounts[0] tpower = TransactingPower(account=account, signer=Web3Signer(testerchain.client)) staker = Staker(transacting_power=tpower, domain=TEMPORARY_DOMAIN, registry=test_registry) # Since StakingEscrow hasn't been activated yet, deposit should work but making a commitment must fail amount = token_economics.minimum_allowed_locked periods = token_economics.minimum_locked_periods staker.initialize_stake(amount=amount, lock_periods=periods) staker.bond_worker(account) with pytest.raises((TransactionFailed, ValueError)): staker.staking_agent.commit_to_next_period(transacting_power=tpower)
def test_beneficiary_withdraws_tokens(testerchain, agent, agency, allocation_value, mock_transacting_power_activation, token_economics): token_agent, staking_agent, policy_agent = agency deployer_address, beneficiary_address, *everybody_else = testerchain.client.accounts contract_address = agent.contract_address assert token_agent.get_balance( address=contract_address ) == agent.unvested_tokens == agent.initial_locked_amount # Trying to withdraw the tokens now fails, obviously initial_amount = token_agent.get_balance(address=contract_address) with pytest.raises((TransactionFailed, ValueError)): agent.withdraw_tokens(value=initial_amount) # Let's deposit some of them (30% of initial amount) staked_amount = 3 * initial_amount // 10 mock_transacting_power_activation(account=agent.beneficiary, password=INSECURE_DEVELOPMENT_PASSWORD) _receipt = agent.deposit_as_staker( amount=staked_amount, lock_periods=token_economics.minimum_locked_periods) # Trying to withdraw the remaining fails too: # The locked amount is equal to the initial deposit (100% of the tokens). # Since 30% are staked, the locked amount is reduced by that 30% when withdrawing, # which results in an effective lock of 70%. However, the contract also has 70%, which means that, effectively, # the beneficiary can only withdraw 0 tokens. assert agent.available_balance == 0 with pytest.raises((TransactionFailed, ValueError)): agent.withdraw_tokens(value=initial_amount - staked_amount) agent.withdraw_tokens(value=0) # Now let's assume the contract has more tokens (e.g., coming from staking rewards). # The beneficiary should be able to collect this excess. mocked_rewards = NU.from_nunits(1000) token_airdrop(token_agent=token_agent, amount=mocked_rewards, origin=deployer_address, addresses=[contract_address]) assert agent.available_balance == mocked_rewards agent.withdraw_tokens(value=int(mocked_rewards)) # Once the lock passes, the beneficiary can withdraw what's left testerchain.time_travel(seconds=TEST_LOCK_DURATION_IN_SECONDS) receipt = agent.withdraw_tokens(value=initial_amount - staked_amount) assert receipt['status'] == 1, "Transaction Rejected" assert token_agent.get_balance(address=contract_address) == 0 assert token_agent.get_balance( address=beneficiary_address ) == initial_amount - staked_amount + mocked_rewards
def staker(testerchain, agency, test_registry, deployer_transacting_power): token_agent = ContractAgency.get_agent(NucypherTokenAgent, registry=test_registry) origin, staker_account, *everybody_else = testerchain.client.accounts staker_power = TransactingPower(account=staker_account, signer=Web3Signer(testerchain.client)) token_airdrop(token_agent=token_agent, transacting_power=deployer_transacting_power, addresses=[staker_account], amount=DEVELOPMENT_TOKEN_AIRDROP_AMOUNT) staker = Staker(domain=TEMPORARY_DOMAIN, transacting_power=staker_power, registry=test_registry) return staker
def funded_blockchain(testerchain, agency, token_economics, test_registry): # Who are ya'? deployer_address, *everyone_else, staking_participant = testerchain.client.accounts # Free ETH!!! testerchain.ether_airdrop(amount=DEVELOPMENT_ETH_AIRDROP_AMOUNT) # Free Tokens!!! token_airdrop(token_agent=NucypherTokenAgent(registry=test_registry), origin=deployer_address, addresses=everyone_else, amount=token_economics.minimum_allowed_locked * 5) # HERE YOU GO yield testerchain, deployer_address
def idle_staker(testerchain, agency, test_registry): token_agent = ContractAgency.get_agent(NucypherTokenAgent, registry=test_registry) idle_staker_account = testerchain.unassigned_accounts[-2] transacting_power = TransactingPower(account=testerchain.etherbase_account, signer=Web3Signer(testerchain.client)) token_airdrop(transacting_power=transacting_power, addresses=[idle_staker_account], token_agent=token_agent, amount=DEVELOPMENT_TOKEN_AIRDROP_AMOUNT) # Prepare idle staker idle_staker = Staker(transacting_power=transacting_power, domain=TEMPORARY_DOMAIN, blockchain=testerchain) yield idle_staker
def stakers(testerchain, agency, token_economics, test_registry): token_agent, _staking_agent, _policy_agent = agency blockchain = token_agent.blockchain # Mock Powerup consumption (Deployer) blockchain.transacting_power = TransactingPower( password=INSECURE_DEVELOPMENT_PASSWORD, signer=Web3Signer(client=testerchain.client), account=blockchain.etherbase_account) blockchain.transacting_power.activate() token_airdrop(origin=blockchain.etherbase_account, addresses=blockchain.stakers_accounts, token_agent=token_agent, amount=DEVELOPMENT_TOKEN_AIRDROP_AMOUNT) stakers = list() for index, account in enumerate(blockchain.stakers_accounts): staker = Staker(is_me=True, checksum_address=account, registry=test_registry) # Mock TransactingPower consumption staker.transacting_power = TransactingPower( password=INSECURE_DEVELOPMENT_PASSWORD, signer=Web3Signer(client=testerchain.client), account=account) staker.transacting_power.activate() amount = MIN_STAKE_FOR_TESTS + random.randrange(BONUS_TOKENS_FOR_TESTS) # for a random lock duration min_locktime, max_locktime = token_economics.minimum_locked_periods, token_economics.maximum_rewarded_periods periods = random.randint(min_locktime, max_locktime) staker.initialize_stake(amount=amount, lock_periods=periods) # We assume that the staker knows in advance the account of her worker worker_address = blockchain.ursula_account(index) staker.bond_worker(worker_address=worker_address) stakers.append(staker) # Stake starts next period (or else signature validation will fail) blockchain.time_travel(periods=1) yield stakers
def idle_staker(testerchain, agency): token_agent, _staking_agent, _policy_agent = agency idle_staker_account = testerchain.unassigned_accounts[-2] # Mock Powerup consumption (Deployer) testerchain.transacting_power = TransactingPower(account=testerchain.etherbase_account) token_airdrop(origin=testerchain.etherbase_account, addresses=[idle_staker_account], token_agent=token_agent, amount=DEVELOPMENT_TOKEN_AIRDROP_AMOUNT) # Prepare idle staker idle_staker = Staker(is_me=True, checksum_address=idle_staker_account, blockchain=testerchain) yield idle_staker
def funded_blockchain(testerchain, agency, application_economics, test_registry): # Who are ya'? deployer_address, *everyone_else, staking_participant = testerchain.client.accounts transacting_power = TransactingPower(account=testerchain.etherbase_account, signer=Web3Signer(testerchain.client)) # Free ETH!!! testerchain.ether_airdrop(amount=DEVELOPMENT_ETH_AIRDROP_AMOUNT) # Free Tokens!!! token_airdrop(token_agent=NucypherTokenAgent(registry=test_registry), transacting_power=transacting_power, addresses=everyone_else, amount=application_economics.min_authorization * 5) # HERE YOU GO yield testerchain, deployer_address
def stakers(testerchain, agency, token_economics, test_registry, deployer_transacting_power): token_agent = ContractAgency.get_agent(NucypherTokenAgent, registry=test_registry) blockchain = token_agent.blockchain token_airdrop(transacting_power=deployer_transacting_power, addresses=blockchain.stakers_accounts, token_agent=token_agent, amount=DEVELOPMENT_TOKEN_AIRDROP_AMOUNT) stakers = list() for index, account in enumerate(blockchain.stakers_accounts): tpower = TransactingPower(account=account, signer=Web3Signer(testerchain.client)) tpower.unlock(password=INSECURE_DEVELOPMENT_PASSWORD) staker = Staker(transacting_power=tpower, domain=TEMPORARY_DOMAIN, registry=test_registry) amount = MIN_STAKE_FOR_TESTS + random.randrange(BONUS_TOKENS_FOR_TESTS) # for a random lock duration min_locktime, max_locktime = token_economics.minimum_locked_periods, token_economics.maximum_rewarded_periods periods = random.randint(min_locktime, max_locktime) staker.initialize_stake(amount=amount, lock_periods=periods) # We assume that the staker knows in advance the account of her worker worker_address = blockchain.ursula_account(index) staker.bond_worker(worker_address=worker_address) stakers.append(staker) # Stake starts next period blockchain.time_travel(periods=1) yield stakers
def test_staker_collects_staking_reward(testerchain, test_registry, staker, blockchain_ursulas, agency, token_economics, mock_transacting_power_activation, ursula_decentralized_test_config): token_agent, staking_agent, policy_agent = agency # Give more tokens to staker token_airdrop(token_agent=token_agent, origin=testerchain.etherbase_account, addresses=[staker.checksum_address], amount=DEVELOPMENT_TOKEN_AIRDROP_AMOUNT) mock_transacting_power_activation(account=staker.checksum_address, password=INSECURE_DEVELOPMENT_PASSWORD) staker.initialize_stake(amount=NU(token_economics.minimum_allowed_locked, 'NuNit'), # Lock the minimum amount of tokens lock_periods=int( token_economics.minimum_locked_periods)) # ... for the fewest number of periods # Get an unused address for a new worker worker_address = testerchain.unassigned_accounts[-1] staker.bond_worker(worker_address=worker_address) # Create this worker and bond it with the staker ursula = make_decentralized_ursulas(ursula_config=ursula_decentralized_test_config, stakers_addresses=[staker.checksum_address], workers_addresses=[worker_address], commit_to_next_period=False, registry=test_registry).pop() # ...mint few tokens... for _ in range(2): transacting_power = ursula._crypto_power.power_ups(TransactingPower) transacting_power.activate(password=INSECURE_DEVELOPMENT_PASSWORD) ursula.commit_to_next_period() testerchain.time_travel(periods=1) # Check mintable periods assert staker.mintable_periods() == 1 ursula.transacting_power.activate(password=INSECURE_DEVELOPMENT_PASSWORD) ursula.commit_to_next_period() # ...wait more... assert staker.mintable_periods() == 0 testerchain.time_travel(periods=2) assert staker.mintable_periods() == 2 mock_transacting_power_activation(account=staker.checksum_address, password=INSECURE_DEVELOPMENT_PASSWORD) # Capture the current token balance of the staker initial_balance = staker.token_balance assert token_agent.get_balance(staker.checksum_address) == initial_balance # Profit! staked = staker.non_withdrawable_stake() owned = staker.owned_tokens() staker.collect_staking_reward() assert staker.owned_tokens() == staked final_balance = staker.token_balance assert final_balance == initial_balance + owned - staked