Beispiel #1
0
    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
Beispiel #2
0
    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
Beispiel #3
0
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)