-
Notifications
You must be signed in to change notification settings - Fork 81
/
signer_list_set.py
146 lines (118 loc) · 4.64 KB
/
signer_list_set.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
"""Model for SignerListSet transaction type."""
from __future__ import annotations
import re
from dataclasses import dataclass, field
from typing import Dict, List, Optional, Pattern
from typing_extensions import Final
from xrpl.models.nested_model import NestedModel
from xrpl.models.required import REQUIRED
from xrpl.models.transactions.transaction import Transaction
from xrpl.models.transactions.types import TransactionType
from xrpl.models.utils import require_kwargs_on_init
MAX_SIGNER_ENTRIES: Final[int] = 32
"""
Maximum number of signer entries allowed.
:meta private:
"""
HEX_WALLET_LOCATOR_REGEX: Final[Pattern[str]] = re.compile("[A-Fa-f0-9]{64}")
"""
Matches hex-encoded WalletLocator in the format allowed by XRPL.
:meta private:
"""
@require_kwargs_on_init
@dataclass(frozen=True)
class SignerEntry(NestedModel):
"""Represents one entry in a list of multi-signers authorized to an account."""
account: str = REQUIRED # type: ignore
"""
This field is required.
:meta hide-value:
"""
signer_weight: int = REQUIRED # type: ignore
"""
This field is required.
:meta hide-value:
"""
wallet_locator: Optional[str] = None
"""
An arbitrary 256-bit (32-byte) field that can be used to identify the signer, which
may be useful for smart contracts, or for identifying who controls a key in a large
organization.
"""
@require_kwargs_on_init
@dataclass(frozen=True)
class SignerListSet(Transaction):
"""
Represents a `SignerListSet <https://xrpl.org/signerlistset.html>`_
transaction, which creates, replaces, or removes a list of signers that
can be used to `multi-sign a transaction
<https://xrpl.org/multi-signing.html>`_.
"""
signer_quorum: int = REQUIRED # type: ignore
"""
This field is required.
:meta hide-value:
"""
signer_entries: Optional[List[SignerEntry]] = None
transaction_type: TransactionType = field(
default=TransactionType.SIGNER_LIST_SET,
init=False,
)
def _get_errors(self: SignerListSet) -> Dict[str, str]:
errors = super()._get_errors()
# deleting a signer list requires self.signer_quorum == 0 and
# self.signer_entries is None
if self.signer_quorum == 0 and self.signer_entries is not None:
errors["signer_list_set"] = (
"Must not include a `signer_entries` value if the signer list is being "
"deleted."
)
if self.signer_quorum != 0 and self.signer_entries is None:
errors["signer_list_set"] = (
"Must have a value of zero for `signer_quorum` if the signer list is "
"being deleted."
)
if self.signer_entries is None: # deletion of the SignerList object
return errors
if self.signer_quorum <= 0:
errors[
"signer_quorum"
] = "`signer_quorum` must be greater than or equal to 0."
if (
len(self.signer_entries) < 1
or len(self.signer_entries) > MAX_SIGNER_ENTRIES
):
errors["signer_entries"] = (
"`signer_entries` must have at least 1 member and no more than {} "
"members. If this transaction is deleting the SignerList, then "
"this parameter must be omitted.".format(MAX_SIGNER_ENTRIES)
)
return errors
account_set = set()
signer_weight_sum = 0
for signer_entry in self.signer_entries:
if signer_entry.account == self.account:
errors["signer_entries"] = (
"The account submitting the transaction cannot appear in a "
"signer entry."
)
if signer_entry.wallet_locator is not None and not bool(
HEX_WALLET_LOCATOR_REGEX.fullmatch(signer_entry.wallet_locator)
):
errors["signer_entries"] = (
"A SignerEntry's wallet_locator must be a 256-bit (32-byte)"
"hexadecimal value."
)
account_set.add(signer_entry.account)
signer_weight_sum += signer_entry.signer_weight
if self.signer_quorum > signer_weight_sum:
errors["signer_quorum"] = (
"`signer_quorum` must be less than or equal to the sum of the "
"SignerWeight values in the `signer_entries` list."
)
if len(account_set) != len(self.signer_entries):
errors["signer_entries"] = (
"An account cannot appear multiple times in the list of signer "
"entries."
)
return errors