def initialize_stake(self, amount: NU, lock_periods: int = None, expiration: maya.MayaDT = None, entire_balance: bool = False) -> Stake: """Create a new stake.""" # # Duration # if lock_periods and expiration: raise ValueError( "Pass the number of lock periods or an expiration MayaDT; not both." ) if expiration: lock_periods = calculate_period_duration(future_time=expiration) # # Value # if entire_balance and amount: raise ValueError("Specify an amount or entire balance, not both") if entire_balance: amount = self.token_balance if not self.token_balance >= amount: raise self.MinerError( f"Insufficient token balance ({self.token_agent}) for new stake initialization of {amount}" ) # Ensure the new stake will not exceed the staking limit if (self.current_stake + amount) > self.economics.maximum_allowed_locked: raise Stake.StakingError( f"Cannot divide stake - Maximum stake value exceeded with a target value of {amount}." ) # # Stake # # Write to blockchain new_stake = Stake.initialize_stake(miner=self, amount=amount, lock_periods=lock_periods) self.__read_stakes() # Update local staking cache return new_stake
def initialize_stake(self, amount: NU, lock_periods: int = None, expiration: maya.MayaDT = None, entire_balance: bool = False) -> Stake: """Create a new stake.""" # Duration if lock_periods and expiration: raise ValueError( "Pass the number of lock periods or an expiration MayaDT; not both." ) if expiration: lock_periods = calculate_period_duration( future_time=expiration, seconds_per_period=self.economics.seconds_per_period) # Value if entire_balance and amount: raise ValueError("Specify an amount or entire balance, not both") if entire_balance: amount = self.token_balance if not self.token_balance >= amount: raise self.InsufficientTokens( f"Insufficient token balance ({self.token_agent}) " f"for new stake initialization of {amount}") # Ensure the new stake will not exceed the staking limit if (self.current_stake + amount) > self.economics.maximum_allowed_locked: raise Stake.StakingError( f"Cannot initialize stake - " f"Maximum stake value exceeded for {self.checksum_address} " f"with a target value of {amount}.") # Write to blockchain new_stake = Stake.initialize_stake(staker=self, amount=amount, lock_periods=lock_periods) # Update staking cache element self.stakes.refresh() return new_stake
def test_stake_validation(mock_testerchain, token_economics, mock_staking_agent): address = mock_testerchain.etherbase_account # Validate stake initialization with pytest.raises(Stake.StakingError): Stake.initialize_stake(staking_agent=mock_staking_agent, checksum_address=address, economics=token_economics, amount=token_economics.minimum_allowed_locked - 1, lock_periods=token_economics.minimum_locked_periods) with pytest.raises(Stake.StakingError): Stake.initialize_stake(staking_agent=mock_staking_agent, checksum_address=address, economics=token_economics, amount=token_economics.minimum_allowed_locked, lock_periods=token_economics.minimum_locked_periods - 1) with pytest.raises(Stake.StakingError): Stake.initialize_stake(staking_agent=mock_staking_agent, checksum_address=address, economics=token_economics, amount=token_economics.maximum_allowed_locked + 1, lock_periods=token_economics.minimum_locked_periods) mock_staking_agent.get_locked_tokens.return_value = 0 Stake.initialize_stake(staking_agent=mock_staking_agent, checksum_address=address, economics=token_economics, amount=token_economics.maximum_allowed_locked, lock_periods=token_economics.minimum_locked_periods) # Validate divide method current_period = 10 mock_staking_agent.get_current_period.return_value = 10 def make_sub_stake(value, first_locked_period, final_locked_period, index=0): return Stake(checksum_address=address, first_locked_period=first_locked_period, final_locked_period=final_locked_period, value=value, index=index, staking_agent=mock_staking_agent, economics=token_economics) nu = NU.from_nunits(2 * token_economics.minimum_allowed_locked - 1) stake = make_sub_stake(first_locked_period=current_period - 2, final_locked_period=current_period + 1, value=nu) with pytest.raises(Stake.StakingError): validate_divide(stake=stake, target_value=token_economics.minimum_allowed_locked, additional_periods=1) stake = make_sub_stake(first_locked_period=current_period - 2, final_locked_period=current_period, value=nu + 1) with pytest.raises(Stake.StakingError): validate_divide(stake=stake, target_value=token_economics.minimum_allowed_locked, additional_periods=1) stake = make_sub_stake(first_locked_period=current_period - 2, final_locked_period=current_period + 1, value=nu + 1) with pytest.raises(Stake.StakingError): validate_divide(stake=stake, target_value=token_economics.minimum_allowed_locked - 1, additional_periods=1) validate_divide(stake=stake, target_value=token_economics.minimum_allowed_locked, additional_periods=1) # Validate prolong method stake = make_sub_stake(first_locked_period=current_period - 2, final_locked_period=current_period, value=nu) with pytest.raises(Stake.StakingError): validate_prolong(stake=stake, additional_periods=1) stake = make_sub_stake(first_locked_period=current_period - 2, final_locked_period=current_period + 2, value=nu) with pytest.raises(Stake.StakingError): validate_prolong(stake=stake, additional_periods=1) with pytest.raises(Stake.StakingError): validate_prolong(stake=stake, additional_periods=token_economics.minimum_locked_periods - 3) validate_prolong(stake=stake, additional_periods=token_economics.minimum_locked_periods - 2) # Validate increase method stake = make_sub_stake(first_locked_period=current_period - 2, final_locked_period=current_period, value=nu) with pytest.raises(Stake.StakingError): validate_increase(stake=stake, amount=nu) stake = make_sub_stake(first_locked_period=current_period - 2, final_locked_period=current_period + 1, value=nu) stake.staking_agent.get_locked_tokens.return_value = nu with pytest.raises(Stake.StakingError): validate_increase(stake=stake, amount=NU.from_nunits(token_economics.maximum_allowed_locked - int(nu) + 1)) validate_increase(stake=stake, amount=NU.from_nunits(token_economics.maximum_allowed_locked - int(nu))) # Validate merge method stake_1 = make_sub_stake(first_locked_period=current_period - 1, final_locked_period=current_period, value=nu, index=0) stake_2 = make_sub_stake(first_locked_period=current_period - 1, final_locked_period=current_period, value=nu, index=1) with pytest.raises(Stake.StakingError): validate_merge(stake_1=stake_1, stake_2=stake_2) stake_1 = make_sub_stake(first_locked_period=current_period - 1, final_locked_period=current_period + 1, value=nu, index=2) stake_2 = make_sub_stake(first_locked_period=current_period - 1, final_locked_period=current_period + 2, value=nu, index=3) with pytest.raises(Stake.StakingError): validate_merge(stake_1=stake_1, stake_2=stake_2) with pytest.raises(Stake.StakingError): validate_merge(stake_1=stake_1, stake_2=stake_1) stake_2 = make_sub_stake(first_locked_period=current_period - 3, final_locked_period=current_period + 1, value=nu, index=4) validate_merge(stake_1=stake_1, stake_2=stake_2)