""" Helper module for signing Harmony staking transactions """ # disable most of the Lint here # pylint: disable=protected-access,no-member,invalid-name,missing-class-docstring,missing-function-docstring from enum import Enum, auto from rlp.sedes import big_endian_int, Binary, CountableList, List, Text from eth_rlp import HashableRLP from eth_utils.curried import ( to_int, hexstr_if_str, ) # https://github.com/harmony-one/sdk/blob/99a827782fabcd5f91f025af0d8de228956d42b4/packages/harmony-staking/src/stakingTransaction.ts#L120 class Directive( Enum ): def _generate_next_value_( name, start, count, last_values ): # pylint: disable=no-self-argument return count CreateValidator = auto() EditValidator = auto() Delegate = auto() Undelegate = auto() CollectRewards = auto() FORMATTERS = { "directive": hexstr_if_str( to_int ), # delegatorAddress is already formatted before the call "nonce": hexstr_if_str(to_int), "gasPrice": hexstr_if_str(to_int), "gasLimit": hexstr_if_str(to_int), "chainId": hexstr_if_str(to_int), } class CollectRewards: @staticmethod def UnsignedChainId(): class UnsignedChainId( HashableRLP ): fields = ( ( "directive", big_endian_int ), ( "stakeMsg", CountableList( Binary.fixed_length( 20, allow_empty = True ) ) ), ( "nonce", big_endian_int ), ( "gasPrice", big_endian_int ), ( "gasLimit", big_endian_int ), ( "chainId", big_endian_int ), ) return UnsignedChainId @staticmethod def SignedChainId(): class SignedChainId( HashableRLP ): fields = CollectRewards.UnsignedChainId()._meta.fields[ :-1 ] + ( # drop chainId ("v", big_endian_int), ("r", big_endian_int), ("s", big_endian_int), ) return SignedChainId @staticmethod def Unsigned(): class Unsigned( HashableRLP ): fields = CollectRewards.UnsignedChainId( )._meta.fields[ :-1 ] # drop chainId return Unsigned @staticmethod def Signed(): class Signed( HashableRLP ): fields = CollectRewards.Unsigned()._meta.fields[ :-3 ] + ( # drop last 3 for raw.pop() ("v", big_endian_int), ("r", big_endian_int), ("s", big_endian_int), ) return Signed class DelegateOrUndelegate: @staticmethod def UnsignedChainId(): class UnsignedChainId( HashableRLP ): fields = ( ( "directive", big_endian_int ), ( "stakeMsg", List( [ Binary.fixed_length( 20, allow_empty = True ), Binary.fixed_length( 20, allow_empty = True ), big_endian_int, ], True, ), ), ( "nonce", big_endian_int ), ( "gasPrice", big_endian_int ), ( "gasLimit", big_endian_int ), ( "chainId", big_endian_int ), ) return UnsignedChainId @staticmethod def SignedChainId(): class SignedChainId( HashableRLP ): fields = DelegateOrUndelegate.UnsignedChainId()._meta.fields[ :-1 ] + ( # drop chainId ("v", big_endian_int), ("r", big_endian_int), ("s", big_endian_int), ) return SignedChainId @staticmethod def Unsigned(): class Unsigned( HashableRLP ): fields = DelegateOrUndelegate.UnsignedChainId( )._meta.fields[ :-1 ] # drop chainId return Unsigned @staticmethod def Signed(): class Signed( HashableRLP ): fields = DelegateOrUndelegate.Unsigned()._meta.fields[ :-3 ] + ( # drop last 3 for raw.pop() ("v", big_endian_int), ("r", big_endian_int), ("s", big_endian_int), ) return Signed class CreateValidator: @staticmethod def UnsignedChainId(): class UnsignedChainId( HashableRLP ): fields = ( ("directive", big_endian_int), ( "stakeMsg", List( [ # list with the following members # validatorAddress Binary.fixed_length( 20, allow_empty=True ), # description is Text of 5 elements List( [Text()] * 5, True ), # commission rate is made up of 3 integers in an array List( [List([big_endian_int], True)] * 3, True ), big_endian_int, # min self delegation big_endian_int, # max total delegation # bls-public-keys array of unspecified length, each key of 48 CountableList( Binary.fixed_length(48, allow_empty=True) ), # bls-key-sigs array of unspecified length, each sig of 96 CountableList( Binary.fixed_length(96, allow_empty=True) ), big_endian_int, # amount ], True, ), ), # strictly these number of elements ("nonce", big_endian_int), ("gasPrice", big_endian_int), ("gasLimit", big_endian_int), ("chainId", big_endian_int), ) return UnsignedChainId @staticmethod def SignedChainId(): class SignedChainId( HashableRLP ): fields = CreateValidator.UnsignedChainId()._meta.fields[ :-1 ] + ( # drop chainId ("v", big_endian_int), ("r", big_endian_int), ("s", big_endian_int), ) return SignedChainId @staticmethod def Unsigned(): class Unsigned( HashableRLP ): fields = CreateValidator.UnsignedChainId( )._meta.fields[ :-1 ] # drop chainId return Unsigned @staticmethod def Signed(): class Signed( HashableRLP ): fields = CreateValidator.Unsigned()._meta.fields[ :-3 ] + ( # drop last 3 for raw.pop() ("v", big_endian_int), ("r", big_endian_int), ("s", big_endian_int), ) return Signed class EditValidator: @staticmethod def UnsignedChainId(): class UnsignedChainId( HashableRLP ): fields = ( ("directive", big_endian_int), ( "stakeMsg", List( [ # list with the following members # validatorAddress Binary.fixed_length( 20, allow_empty=True ), # description is Text of 5 elements List( [Text()] * 5, True ), # new rate is in a list List([big_endian_int], True), big_endian_int, # min self delegation big_endian_int, # max total delegation # slot key to remove Binary.fixed_length( 48, allow_empty=True ), # slot key to add Binary.fixed_length( 48, allow_empty=True ), # slot key to add sig Binary.fixed_length( 96, allow_empty=True ), ], True, ), ), # strictly these number of elements ("nonce", big_endian_int), ("gasPrice", big_endian_int), ("gasLimit", big_endian_int), ("chainId", big_endian_int), ) return UnsignedChainId @staticmethod def SignedChainId(): class SignedChainId( HashableRLP ): fields = EditValidator.UnsignedChainId()._meta.fields[ :-1 ] + ( # drop chainId ("v", big_endian_int), ("r", big_endian_int), ("s", big_endian_int), ) return SignedChainId @staticmethod def Unsigned(): class Unsigned( HashableRLP ): fields = EditValidator.UnsignedChainId( )._meta.fields[ :-1 ] # drop chainId return Unsigned @staticmethod def Signed(): class Signed( HashableRLP ): fields = EditValidator.Unsigned()._meta.fields[ :-3 ] + ( # drop last 3 for raw.pop() ("v", big_endian_int), ("r", big_endian_int), ("s", big_endian_int), ) return Signed