mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-29 15:37:57 +00:00
367 lines
12 KiB
Python
367 lines
12 KiB
Python
import datetime
|
|
import json
|
|
from typing import Dict, List, Optional, Union
|
|
|
|
from command import Command
|
|
from common import Account, Asset, Path, PathList, to_rippled_epoch
|
|
|
|
|
|
class Transaction(Command):
|
|
'''Interface for all transactions'''
|
|
def __init__(
|
|
self,
|
|
*,
|
|
account: Account,
|
|
flags: Optional[int] = None,
|
|
fee: Optional[Union[Asset, int]] = None,
|
|
sequence: Optional[int] = None,
|
|
account_txn_id: Optional[str] = None,
|
|
last_ledger_sequence: Optional[int] = None,
|
|
src_tag: Optional[int] = None,
|
|
memos: Optional[List[Dict[str, dict]]] = None,
|
|
):
|
|
super().__init__()
|
|
self.account = account
|
|
# set even if None
|
|
self.flags = flags
|
|
self.fee = fee
|
|
self.sequence = sequence
|
|
self.account_txn_id = account_txn_id
|
|
self.last_ledger_sequence = last_ledger_sequence
|
|
self.src_tag = src_tag
|
|
self.memos = memos
|
|
|
|
def cmd_name(self) -> str:
|
|
return 'submit'
|
|
|
|
def set_seq_and_fee(self, seq: int, fee: Union[Asset, int]):
|
|
self.sequence = seq
|
|
self.fee = fee
|
|
|
|
def to_cmd_obj(self) -> dict:
|
|
txn = {
|
|
'Account': self.account.account_id,
|
|
}
|
|
if self.flags is not None:
|
|
txn['Flags'] = flags
|
|
if self.fee is not None:
|
|
if isinstance(self.fee, int):
|
|
txn['Fee'] = f'{self.fee}' # must be a string
|
|
else:
|
|
txn['Fee'] = self.fee.to_cmd_obj()
|
|
if self.sequence is not None:
|
|
txn['Sequence'] = self.sequence
|
|
if self.account_txn_id is not None:
|
|
txn['AccountTxnID'] = self.account_txn_id
|
|
if self.last_ledger_sequence is not None:
|
|
txn['LastLedgerSequence'] = self.last_ledger_sequence
|
|
if self.src_tag is not None:
|
|
txn['SourceTag'] = self.src_tag
|
|
if self.memos is not None:
|
|
txn['Memos'] = self.memos
|
|
return txn
|
|
|
|
|
|
class Payment(Transaction):
|
|
'''A payment transaction'''
|
|
def __init__(self,
|
|
*,
|
|
dst: Account,
|
|
amt: Asset,
|
|
send_max: Optional[Asset] = None,
|
|
paths: Optional[PathList] = None,
|
|
dst_tag: Optional[int] = None,
|
|
deliver_min: Optional[Asset] = None,
|
|
**rest):
|
|
super().__init__(**rest)
|
|
self.dst = dst
|
|
self.amt = amt
|
|
self.send_max = send_max
|
|
if paths is not None and isinstance(paths, Path):
|
|
# allow paths = Path([...]) special case
|
|
self.paths = PathList([paths])
|
|
else:
|
|
self.paths = paths
|
|
self.dst_tag = dst_tag
|
|
self.deliver_min = deliver_min
|
|
|
|
def set_partial_payment(self, value: bool = True):
|
|
'''Set or clear the partial payment flag'''
|
|
self._set_flag(0x0002_0000, value)
|
|
|
|
def to_cmd_obj(self) -> dict:
|
|
'''convert to transaction form (suitable for using json.dumps or similar)'''
|
|
txn = super().to_cmd_obj()
|
|
txn = {
|
|
**txn,
|
|
'TransactionType': 'Payment',
|
|
'Destination': self.dst.account_id,
|
|
'Amount': self.amt.to_cmd_obj(),
|
|
}
|
|
if self.paths is not None:
|
|
txn['Paths'] = self.paths.to_cmd_obj()
|
|
if self.send_max is not None:
|
|
txn['SendMax'] = self.send_max.to_cmd_obj()
|
|
if self.dst_tag is not None:
|
|
txn['DestinationTag'] = self.dst_tag
|
|
if self.deliver_min is not None:
|
|
txn['DeliverMin'] = self.deliver_min
|
|
return txn
|
|
|
|
|
|
class Trust(Transaction):
|
|
'''A trust set transaction'''
|
|
def __init__(self,
|
|
*,
|
|
limit_amt: Optional[Asset] = None,
|
|
qin: Optional[int] = None,
|
|
qout: Optional[int] = None,
|
|
**rest):
|
|
super().__init__(**rest)
|
|
self.limit_amt = limit_amt
|
|
self.qin = qin
|
|
self.qout = qout
|
|
|
|
def set_auth(self):
|
|
'''Set the auth flag (cannot be cleared)'''
|
|
self._set_flag(0x00010000)
|
|
return self
|
|
|
|
def set_no_ripple(self, value: bool = True):
|
|
'''Set or clear the noRipple flag'''
|
|
self._set_flag(0x0002_0000, value)
|
|
self._set_flag(0x0004_0000, not value)
|
|
return self
|
|
|
|
def set_freeze(self, value: bool = True):
|
|
'''Set or clear the freeze flag'''
|
|
self._set_flag(0x0020_0000, value)
|
|
self._set_flag(0x0040_0000, not value)
|
|
return self
|
|
|
|
def to_cmd_obj(self) -> dict:
|
|
'''convert to transaction form (suitable for using json.dumps or similar)'''
|
|
result = super().to_cmd_obj()
|
|
result = {
|
|
**result,
|
|
'TransactionType': 'TrustSet',
|
|
'LimitAmount': self.limit_amt.to_cmd_obj(),
|
|
}
|
|
if self.qin is not None:
|
|
result['QualityIn'] = self.qin
|
|
if self.qout is not None:
|
|
result['QualityOut'] = self.qout
|
|
return result
|
|
|
|
|
|
class SetRegularKey(Transaction):
|
|
'''A SetRegularKey transaction'''
|
|
def __init__(self, *, key: str, **rest):
|
|
super().__init__(**rest)
|
|
self.key = key
|
|
|
|
def to_cmd_obj(self) -> dict:
|
|
'''convert to transaction form (suitable for using json.dumps or similar)'''
|
|
result = super().to_cmd_obj()
|
|
result = {
|
|
**result,
|
|
'TransactionType': 'SetRegularKey',
|
|
'RegularKey': self.key,
|
|
}
|
|
return result
|
|
|
|
|
|
class SignerListSet(Transaction):
|
|
'''A SignerListSet transaction'''
|
|
def __init__(self,
|
|
*,
|
|
keys: List[str],
|
|
weights: Optional[List[int]] = None,
|
|
quorum: int,
|
|
**rest):
|
|
super().__init__(**rest)
|
|
self.keys = keys
|
|
self.quorum = quorum
|
|
if weights:
|
|
if len(weights) != len(keys):
|
|
raise ValueError(
|
|
f'SignerSetList number of weights must equal number of keys (or be empty). Weights: {weights} Keys: {keys}'
|
|
)
|
|
self.weights = weights
|
|
else:
|
|
self.weights = [1] * len(keys)
|
|
|
|
def to_cmd_obj(self) -> dict:
|
|
'''convert to transaction form (suitable for using json.dumps or similar)'''
|
|
result = super().to_cmd_obj()
|
|
result = {
|
|
**result,
|
|
'TransactionType': 'SignerListSet',
|
|
'SignerQuorum': self.quorum,
|
|
}
|
|
entries = []
|
|
for k, w in zip(self.keys, self.weights):
|
|
entries.append({'SignerEntry': {'Account': k, 'SignerWeight': w}})
|
|
result['SignerEntries'] = entries
|
|
return result
|
|
|
|
|
|
class AccountSet(Transaction):
|
|
'''An account set transaction'''
|
|
def __init__(self, account: Account, **rest):
|
|
super().__init__(account=account, **rest)
|
|
self.clear_flag = None
|
|
self.set_flag = None
|
|
self.transfer_rate = None
|
|
self.tick_size = None
|
|
|
|
def _set_account_flag(self, flag_id: int, value):
|
|
if value:
|
|
self.set_flag = flag_id
|
|
else:
|
|
self.clear_flag = flag_id
|
|
return self
|
|
|
|
def set_account_txn_id(self, value: bool = True):
|
|
'''Set or clear the asfAccountTxnID flag'''
|
|
return self._set_account_flag(5, value)
|
|
|
|
def set_default_ripple(self, value: bool = True):
|
|
'''Set or clear the asfDefaultRipple flag'''
|
|
return self._set_account_flag(8, value)
|
|
|
|
def set_deposit_auth(self, value: bool = True):
|
|
'''Set or clear the asfDepositAuth flag'''
|
|
return self._set_account_flag(9, value)
|
|
|
|
def set_disable_master(self, value: bool = True):
|
|
'''Set or clear the asfDisableMaster flag'''
|
|
return self._set_account_flag(4, value)
|
|
|
|
def set_disallow_xrp(self, value: bool = True):
|
|
'''Set or clear the asfDisallowXRP flag'''
|
|
return self._set_account_flag(3, value)
|
|
|
|
def set_global_freeze(self, value: bool = True):
|
|
'''Set or clear the asfGlobalFreeze flag'''
|
|
return self._set_account_flag(7, value)
|
|
|
|
def set_no_freeze(self, value: bool = True):
|
|
'''Set or clear the asfNoFreeze flag'''
|
|
return self._set_account_flag(6, value)
|
|
|
|
def set_require_auth(self, value: bool = True):
|
|
'''Set or clear the asfRequireAuth flag'''
|
|
return self._set_account_flag(2, value)
|
|
|
|
def set_require_dest(self, value: bool = True):
|
|
'''Set or clear the asfRequireDest flag'''
|
|
return self._set_account_flag(1, value)
|
|
|
|
def set_transfer_rate(self, value: int):
|
|
'''Set the fee to change when users transfer this account's issued currencies'''
|
|
self.transfer_rate = value
|
|
return self
|
|
|
|
def set_tick_size(self, value: int):
|
|
'''Tick size to use for offers involving a currency issued by this address'''
|
|
self.tick_size = value
|
|
return self
|
|
|
|
def to_cmd_obj(self) -> dict:
|
|
'''convert to transaction form (suitable for using json.dumps or similar)'''
|
|
result = super().to_cmd_obj()
|
|
result = {
|
|
**result,
|
|
'TransactionType': 'AccountSet',
|
|
}
|
|
if self.clear_flag is not None:
|
|
result['ClearFlag'] = self.clear_flag
|
|
if self.set_flag is not None:
|
|
result['SetFlag'] = self.set_flag
|
|
if self.transfer_rate is not None:
|
|
result['TransferRate'] = self.transfer_rate
|
|
if self.tick_size is not None:
|
|
result['TickSize'] = self.tick_size
|
|
return result
|
|
|
|
|
|
class Offer(Transaction):
|
|
'''An offer transaction'''
|
|
def __init__(self,
|
|
*,
|
|
taker_pays: Asset,
|
|
taker_gets: Asset,
|
|
expiration: Optional[int] = None,
|
|
offer_sequence: Optional[int] = None,
|
|
**rest):
|
|
super().__init__(**rest)
|
|
self.taker_pays = taker_pays
|
|
self.taker_gets = taker_gets
|
|
self.expiration = expiration
|
|
self.offer_sequence = offer_sequence
|
|
|
|
def set_passive(self, value: bool = True):
|
|
return self._set_flag(0x0001_0000, value)
|
|
|
|
def set_immediate_or_cancel(self, value: bool = True):
|
|
return self._set_flag(0x0002_0000, value)
|
|
|
|
def set_fill_or_kill(self, value: bool = True):
|
|
return self._set_flag(0x0004_0000, value)
|
|
|
|
def set_sell(self, value: bool = True):
|
|
return self._set_flag(0x0008_0000, value)
|
|
|
|
def to_cmd_obj(self) -> dict:
|
|
txn = super().to_cmd_obj()
|
|
txn = {
|
|
**txn,
|
|
'TransactionType': 'OfferCreate',
|
|
'TakerPays': self.taker_pays.to_cmd_obj(),
|
|
'TakerGets': self.taker_gets.to_cmd_obj(),
|
|
}
|
|
if self.expiration is not None:
|
|
txn['Expiration'] = self.expiration
|
|
if self.offer_sequence is not None:
|
|
txn['OfferSequence'] = self.offer_sequence
|
|
return txn
|
|
|
|
|
|
class Ticket(Transaction):
|
|
'''A ticket create transaction'''
|
|
def __init__(self, *, count: int = 1, **rest):
|
|
super().__init__(**rest)
|
|
self.count = count
|
|
|
|
def to_cmd_obj(self) -> dict:
|
|
txn = super().to_cmd_obj()
|
|
txn = {
|
|
**txn,
|
|
'TransactionType': 'TicketCreate',
|
|
'TicketCount': self.count,
|
|
}
|
|
return txn
|
|
|
|
|
|
class SetHook(Transaction):
|
|
'''A SetHook transaction for the experimental hook amendment'''
|
|
def __init__(self,
|
|
*,
|
|
create_code: str,
|
|
hook_on: str = '0000000000000000',
|
|
**rest):
|
|
super().__init__(**rest)
|
|
self.create_code = create_code
|
|
self.hook_on = hook_on
|
|
|
|
def to_cmd_obj(self) -> dict:
|
|
txn = super().to_cmd_obj()
|
|
txn = {
|
|
**txn,
|
|
'TransactionType': 'SetHook',
|
|
'CreateCode': self.create_code,
|
|
'HookOn': self.hook_on,
|
|
}
|
|
return txn
|