-
Notifications
You must be signed in to change notification settings - Fork 85
/
payment.py
169 lines (138 loc) · 5.72 KB
/
payment.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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
"""Model for Payment transaction type and related flags."""
from __future__ import annotations # Requires Python 3.7+
from dataclasses import dataclass, field
from enum import Enum
from typing import Dict, List, Optional
from xrpl.models.amounts import Amount, is_xrp
from xrpl.models.flags import FlagInterface
from xrpl.models.path import Path
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
class PaymentFlag(int, Enum):
"""
Transactions of the Payment type support additional values in the Flags field.
This enum represents those options.
`See Payment Flags <https://xrpl.org/payment.html#payment-flags>`_
"""
TF_NO_DIRECT_RIPPLE = 0x00010000
"""
Do not use the default path; only use paths included in the Paths field.
This is intended to force the transaction to take arbitrage opportunities.
Most clients do not need this.
"""
TF_PARTIAL_PAYMENT = 0x00020000
"""
If the specified Amount cannot be sent without spending more than SendMax,
reduce the received amount instead of failing outright.
See `Partial Payments <https://xrpl.org/partial-payments.html>`_ for more details.
"""
TF_LIMIT_QUALITY = 0x00040000
"""
Only take paths where all the conversions have an input:output ratio
that is equal or better than the ratio of Amount:SendMax.
See `Limit <https://xrpl.org/payment.html#limit-quality>`_ Quality for details.
"""
class PaymentFlagInterface(FlagInterface):
"""
Transactions of the Payment type support additional values in the Flags field.
This TypedDict represents those options.
`See Payment Flags <https://xrpl.org/payment.html#payment-flags>`_
"""
TF_NO_DIRECT_RIPPLE: bool
TF_PARTIAL_PAYMENT: bool
TF_LIMIT_QUALITY: bool
@require_kwargs_on_init
@dataclass(frozen=True)
class Payment(Transaction):
"""
Represents a Payment <https://xrpl.org/payment.html>`_ transaction, which
sends value from one account to another. (Depending on the path taken, this
can involve additional exchanges of value, which occur atomically.) This
transaction type can be used for several `types of payments
<http://xrpl.local/payment.html#types-of-payments>`_.
Payments are also the only way to `create accounts
<http://xrpl.local/payment.html#creating-accounts>`_.
"""
amount: Amount = REQUIRED # type: ignore
"""
The amount of currency to deliver. If the Partial Payment flag is set,
deliver *up to* this amount instead. This field is required.
:meta hide-value:
"""
destination: str = REQUIRED # type: ignore
"""
The address of the account receiving the payment. This field is required.
:meta hide-value:
"""
destination_tag: Optional[int] = None
"""
An arbitrary `destination tag
<https://xrpl.org/source-and-destination-tags.html>`_ that
identifies the reason for the Payment, or a hosted recipient to pay.
"""
invoice_id: Optional[str] = None # TODO: should be a 256 bit hash
"""
Arbitrary 256-bit hash representing a specific reason or identifier for
this Check.
"""
paths: Optional[List[Path]] = None
"""
Array of payment paths to be used (for a cross-currency payment). Must be
omitted for XRP-to-XRP transactions.
"""
send_max: Optional[Amount] = None
"""
Maximum amount of source currency this transaction is allowed to cost,
including `transfer fees <http://xrpl.local/transfer-fees.html>`_,
exchange rates, and slippage. Does not include the XRP destroyed as a
cost for submitting the transaction. Must be supplied for cross-currency
or cross-issue payments. Must be omitted for XRP-to-XRP payments.
"""
deliver_min: Optional[Amount] = None
"""
Minimum amount of destination currency this transaction should deliver.
Only valid if this is a partial payment. If omitted, any positive amount
is considered a success.
"""
transaction_type: TransactionType = field(
default=TransactionType.PAYMENT,
init=False,
)
def _get_errors(self: Payment) -> Dict[str, str]:
errors = super()._get_errors()
# XRP transaction errors
if is_xrp(self.amount) and self.send_max is None:
if self.paths is not None:
errors["paths"] = "An XRP-to-XRP payment cannot contain paths."
if self.account == self.destination:
errors["destination"] = (
"An XRP payment transaction cannot have the same sender and "
"destination."
)
# partial payment errors
elif self.has_flag(PaymentFlag.TF_PARTIAL_PAYMENT) and self.send_max is None:
errors["send_max"] = "A partial payment must have a `send_max` value."
elif self.deliver_min is not None and not self.has_flag(
PaymentFlag.TF_PARTIAL_PAYMENT
):
errors[
"deliver_min"
] = "A non-partial payment cannot have a `deliver_min` field."
elif (
is_xrp(self.amount)
and (self.send_max and is_xrp(self.send_max))
and not self.has_flag(PaymentFlag.TF_PARTIAL_PAYMENT)
):
errors["send_max"] = (
"A non-partial payment cannot have both ``amount`` and `send_max` be "
"XRP."
)
# currency conversion errors
elif self.account == self.destination:
if self.send_max is None:
errors[
"send_max"
] = "A currency conversion requires a `send_max` value."
return errors