From 8d6c1cc0caeca1cd0655084a075158379db62a50 Mon Sep 17 00:00:00 2001 From: overcat <4catcode@gmail.com> Date: Tue, 22 Sep 2020 22:49:03 +0800 Subject: [PATCH 01/12] WIP --- stellar_sdk/operation/begin_sponsoring_future_reserves.py | 2 ++ stellar_sdk/operation/end_sponsoring_future_reserves.py | 2 ++ stellar_sdk/operation/revoke_sponsorship.py | 2 ++ 3 files changed, 6 insertions(+) create mode 100644 stellar_sdk/operation/begin_sponsoring_future_reserves.py create mode 100644 stellar_sdk/operation/end_sponsoring_future_reserves.py create mode 100644 stellar_sdk/operation/revoke_sponsorship.py diff --git a/stellar_sdk/operation/begin_sponsoring_future_reserves.py b/stellar_sdk/operation/begin_sponsoring_future_reserves.py new file mode 100644 index 00000000..35a7a3cb --- /dev/null +++ b/stellar_sdk/operation/begin_sponsoring_future_reserves.py @@ -0,0 +1,2 @@ +class BeginSponsoringFutureReserves: + pass diff --git a/stellar_sdk/operation/end_sponsoring_future_reserves.py b/stellar_sdk/operation/end_sponsoring_future_reserves.py new file mode 100644 index 00000000..f02a5b69 --- /dev/null +++ b/stellar_sdk/operation/end_sponsoring_future_reserves.py @@ -0,0 +1,2 @@ +class EndSponsoringFutureReserves: + pass \ No newline at end of file diff --git a/stellar_sdk/operation/revoke_sponsorship.py b/stellar_sdk/operation/revoke_sponsorship.py new file mode 100644 index 00000000..7779d7c7 --- /dev/null +++ b/stellar_sdk/operation/revoke_sponsorship.py @@ -0,0 +1,2 @@ +class RevokeSponsorship: + pass \ No newline at end of file From d5f3cb166d5a2f33cc9fa0c8acd0e59cfb2e7b5d Mon Sep 17 00:00:00 2001 From: overcat <4catcode@gmail.com> Date: Tue, 22 Sep 2020 23:51:02 +0800 Subject: [PATCH 02/12] WIP --- .../begin_sponsoring_future_reserves.py | 42 ++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/stellar_sdk/operation/begin_sponsoring_future_reserves.py b/stellar_sdk/operation/begin_sponsoring_future_reserves.py index 35a7a3cb..5c3453ca 100644 --- a/stellar_sdk/operation/begin_sponsoring_future_reserves.py +++ b/stellar_sdk/operation/begin_sponsoring_future_reserves.py @@ -1,2 +1,40 @@ -class BeginSponsoringFutureReserves: - pass +from .operation import Operation +from .utils import check_ed25519_public_key +from ..keypair import Keypair +from ..strkey import StrKey +from ..xdr import Xdr + + +class BeginSponsoringFutureReserves(Operation): + def __init__(self, sponsored_id: str, source: str = None) -> None: + super().__init__(source) + check_ed25519_public_key(sponsored_id) + self.sponsored_id: str = sponsored_id + + @classmethod + def type_code(cls) -> int: + return Xdr.const.BEGIN_SPONSORING_FUTURE_RESERVES + + def _to_operation_body(self) -> Xdr.nullclass: + sponsored_id = Keypair.from_public_key(self.sponsored_id).xdr_account_id() + begin_sponsoring_future_reserves_op = Xdr.types.BeginSponsoringFutureReservesOp(sponsoredID=sponsored_id) + body = Xdr.nullclass() + body.type = Xdr.const.BEGIN_SPONSORING_FUTURE_RESERVES + body.beginSponsoringFutureReservesOp = begin_sponsoring_future_reserves_op + return body + + @classmethod + def from_xdr_object( + cls, operation_xdr_object: Xdr.types.Operation + ) -> "BeginSponsoringFutureReserves": + """Creates a :class:`BeginSponsoringFutureReserves` object from an XDR Operation + object. + """ + source = Operation.get_source_from_xdr_obj(operation_xdr_object) + + sponsored_id = StrKey.encode_ed25519_public_key( + operation_xdr_object.body.beginSponsoringFutureReservesOp.sponsoredID.ed25519 + ) + op = cls(source=source, sponsored_id=sponsored_id) + op._source_muxed = Operation.get_source_muxed_from_xdr_obj(operation_xdr_object) + return op From 2acc2176857f1a66c7293200649a1779596c40ba Mon Sep 17 00:00:00 2001 From: overcat <4catcode@gmail.com> Date: Tue, 22 Sep 2020 23:59:20 +0800 Subject: [PATCH 03/12] WIP --- .../end_sponsoring_future_reserves.py | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/stellar_sdk/operation/end_sponsoring_future_reserves.py b/stellar_sdk/operation/end_sponsoring_future_reserves.py index f02a5b69..70f699b9 100644 --- a/stellar_sdk/operation/end_sponsoring_future_reserves.py +++ b/stellar_sdk/operation/end_sponsoring_future_reserves.py @@ -1,2 +1,28 @@ -class EndSponsoringFutureReserves: - pass \ No newline at end of file +from .operation import Operation +from ..xdr import Xdr + + +class EndSponsoringFutureReserves(Operation): + def __init__(self, source: str = None) -> None: + super().__init__(source) + + @classmethod + def type_code(cls) -> int: + return Xdr.const.END_SPONSORING_FUTURE_RESERVES + + def _to_operation_body(self) -> Xdr.nullclass: + body = Xdr.nullclass() + body.type = Xdr.const.END_SPONSORING_FUTURE_RESERVES + return body + + @classmethod + def from_xdr_object( + cls, operation_xdr_object: Xdr.types.Operation + ) -> "EndSponsoringFutureReserves": + """Creates a :class:`EndSponsoringFutureReserves` object from an XDR Operation + object. + """ + source = Operation.get_source_from_xdr_obj(operation_xdr_object) + op = cls(source=source, ) + op._source_muxed = Operation.get_source_muxed_from_xdr_obj(operation_xdr_object) + return op From 3474f1aacfb128a72e622e474363544ad2dd608b Mon Sep 17 00:00:00 2001 From: overcat <4catcode@gmail.com> Date: Wed, 23 Sep 2020 23:36:45 +0800 Subject: [PATCH 04/12] WIP --- stellar_sdk/operation/revoke_sponsorship.py | 141 +++++++++++++++++++- 1 file changed, 139 insertions(+), 2 deletions(-) diff --git a/stellar_sdk/operation/revoke_sponsorship.py b/stellar_sdk/operation/revoke_sponsorship.py index 7779d7c7..51c9ea6a 100644 --- a/stellar_sdk/operation/revoke_sponsorship.py +++ b/stellar_sdk/operation/revoke_sponsorship.py @@ -1,2 +1,139 @@ -class RevokeSponsorship: - pass \ No newline at end of file +import binascii +from enum import IntEnum + +from .operation import Operation +from ..asset import Asset +from ..keypair import Keypair +from ..signer import Signer as XDRSigner +from ..xdr import Xdr + + +class RevokeSponsorshipType(IntEnum): + ACCOUNT = 0 + TRUSTLINE = 1 + OFFER = 2 + DATA = 3 + CLAIMABLE_BALANCE = 4 + SIGNER = 5 + + +class TrustLine: + def __init__(self, account_id: str, asset: Asset): + self.account_id = account_id + self.asset = asset + + +class Offer: + def __init__(self, seller_id: str, offer_id: int): + self.seller_id = seller_id + self.offer_id = offer_id + + +class Data: + def __init__(self, account_id: str, data_name: str): + self.account_id = account_id + self.data_name = data_name + + +class Signer: + def __init__(self, account_id: str, signer_key: XDRSigner): + self.account_id = account_id + self.signer_key = signer_key + + +class RevokeSponsorship(Operation): + def __init__(self, + revoke_sponsorship_type: RevokeSponsorshipType, + account_id: str, + trustline: TrustLine, + offer: Offer, + data: Data, + claimable_balance_id: str, + signer: Signer, + source: str = None): + super().__init__(source) + self.revoke_sponsorship_type = revoke_sponsorship_type + self.account_id = account_id + self.trustline = trustline + self.offer = offer + self.data = data + if isinstance(claimable_balance_id, str): + claimable_balance_id = binascii.unhexlify(claimable_balance_id) + self.claimable_balance_id: bytes = claimable_balance_id + self.signer = signer + + @classmethod + def type_code(cls) -> int: + return Xdr.const.REVOKE_SPONSORSHIP + + def _to_operation_body(self) -> Xdr.nullclass: + body = Xdr.nullclass() + body.type = Xdr.const.REVOKE_SPONSORSHIP + if self.revoke_sponsorship_type == RevokeSponsorshipType.ACCOUNT: + ledger_key = Xdr.nullclass() + ledger_key.type = Xdr.const.ACCOUNT + account = Xdr.nullclass() + account.accountID = Keypair.from_public_key(self.account_id).xdr_account_id() + ledger_key.account = account + revoke_sponsorship_op = Xdr.nullclass() + revoke_sponsorship_op.type = Xdr.const.REVOKE_SPONSORSHIP_LEDGER_ENTRY + revoke_sponsorship_op.ledgerKey = ledger_key + body.revokeSponsorshipOp = revoke_sponsorship_op + return body + elif self.revoke_sponsorship_type == RevokeSponsorshipType.TRUSTLINE: + ledger_key = Xdr.nullclass() + ledger_key.type = Xdr.const.TRUSTLINE + trust_line = Xdr.nullclass() + trust_line.accountID = Keypair.from_public_key(self.trustline.account_id).xdr_account_id() + trust_line.asset = self.trustline.asset.to_xdr_object() + ledger_key.trustLine = trust_line + revoke_sponsorship_op = Xdr.nullclass() + revoke_sponsorship_op.type = Xdr.const.REVOKE_SPONSORSHIP_LEDGER_ENTRY + revoke_sponsorship_op.ledgerKey = ledger_key + body.revokeSponsorshipOp = revoke_sponsorship_op + return body + elif self.revoke_sponsorship_type == RevokeSponsorshipType.OFFER: + ledger_key = Xdr.nullclass() + ledger_key.type = Xdr.const.OFFER + offer = Xdr.nullclass() + offer.sellerID = Keypair.from_public_key(self.offer.seller_id).xdr_account_id() + offer.offerID = self.offer.offer_id + ledger_key.offer = offer + revoke_sponsorship_op = Xdr.nullclass() + revoke_sponsorship_op.type = Xdr.const.REVOKE_SPONSORSHIP_LEDGER_ENTRY + revoke_sponsorship_op.ledgerKey = ledger_key + body.revokeSponsorshipOp = revoke_sponsorship_op + return body + elif self.revoke_sponsorship_type == RevokeSponsorshipType.DATA: + ledger_key = Xdr.nullclass() + ledger_key.type = Xdr.const.DATA + data = Xdr.nullclass() + data.accountID = Keypair.from_public_key(self.data.account_id).xdr_account_id() + data.dataName = self.data.data_name + ledger_key.account = data + revoke_sponsorship_op = Xdr.nullclass() + revoke_sponsorship_op.type = Xdr.const.REVOKE_SPONSORSHIP_LEDGER_ENTRY + revoke_sponsorship_op.ledgerKey = ledger_key + body.revokeSponsorshipOp = revoke_sponsorship_op + return body + elif self.revoke_sponsorship_type == RevokeSponsorshipType.CLAIMABLE_BALANCE: + ledger_key = Xdr.nullclass() + ledger_key.type = Xdr.const.CLAIMABLE_BALANCE + claimable_balance = Xdr.nullclass() + claimable_balance.accountID = Keypair.from_public_key(self.data.account_id).xdr_account_id() + ledger_key.claimableBalance = claimable_balance + revoke_sponsorship_op = Xdr.nullclass() + revoke_sponsorship_op.type = Xdr.const.REVOKE_SPONSORSHIP_LEDGER_ENTRY + revoke_sponsorship_op.ledgerKey = ledger_key + body.revokeSponsorshipOp = revoke_sponsorship_op + return body + elif self.revoke_sponsorship_type == RevokeSponsorshipType.SIGNER: + signer = Xdr.nullclass() + signer.accountID = Keypair.from_public_key(self.signer.account_id).xdr_account_id() + signer.signerKey = self.signer.signer_key.to_xdr_object() + revoke_sponsorship_op = Xdr.nullclass() + revoke_sponsorship_op.type = Xdr.const.REVOKE_SPONSORSHIP_SIGNER + revoke_sponsorship_op.signer = signer + body.revokeSponsorshipOp = revoke_sponsorship_op + else: + raise ValueError From 27fb7af4c720ea9d7d6a99b00e54579505a395d4 Mon Sep 17 00:00:00 2001 From: overcat <4catcode@gmail.com> Date: Wed, 30 Sep 2020 17:34:11 +0800 Subject: [PATCH 05/12] WIP --- stellar_sdk/operation/__init__.py | 6 + .../begin_sponsoring_future_reserves.py | 6 +- .../end_sponsoring_future_reserves.py | 4 +- stellar_sdk/operation/revoke_sponsorship.py | 223 ++++++++++++++++-- stellar_sdk/signer.py | 40 +--- stellar_sdk/signer_key.py | 91 +++++++ tests/test_operation.py | 136 +++++++++++ 7 files changed, 446 insertions(+), 60 deletions(-) create mode 100644 stellar_sdk/signer_key.py diff --git a/stellar_sdk/operation/__init__.py b/stellar_sdk/operation/__init__.py index c9f85abe..8cc4eb19 100644 --- a/stellar_sdk/operation/__init__.py +++ b/stellar_sdk/operation/__init__.py @@ -1,9 +1,11 @@ from .account_merge import AccountMerge from .allow_trust import AllowTrust, TrustLineEntryFlag +from .begin_sponsoring_future_reserves import BeginSponsoringFutureReserves from .bump_sequence import BumpSequence from .change_trust import ChangeTrust from .create_account import CreateAccount from .create_passive_sell_offer import CreatePassiveSellOffer +from .end_sponsoring_future_reserves import EndSponsoringFutureReserves from .inflation import Inflation from .manage_buy_offer import ManageBuyOffer from .manage_data import ManageData @@ -13,6 +15,7 @@ from .path_payment_strict_receive import PathPaymentStrictReceive from .path_payment_strict_send import PathPaymentStrictSend from .payment import Payment +from .revoke_sponsorship import RevokeSponsorship from .set_options import SetOptions, Flag __all__ = [ @@ -32,6 +35,9 @@ "PathPaymentStrictSend", "Payment", "SetOptions", + "BeginSponsoringFutureReserves", + "EndSponsoringFutureReserves", + "RevokeSponsorship", "TrustLineEntryFlag", "Flag", # TODO: act like TrustLineEntryFlag ] diff --git a/stellar_sdk/operation/begin_sponsoring_future_reserves.py b/stellar_sdk/operation/begin_sponsoring_future_reserves.py index 5c3453ca..dda3c244 100644 --- a/stellar_sdk/operation/begin_sponsoring_future_reserves.py +++ b/stellar_sdk/operation/begin_sponsoring_future_reserves.py @@ -17,7 +17,9 @@ def type_code(cls) -> int: def _to_operation_body(self) -> Xdr.nullclass: sponsored_id = Keypair.from_public_key(self.sponsored_id).xdr_account_id() - begin_sponsoring_future_reserves_op = Xdr.types.BeginSponsoringFutureReservesOp(sponsoredID=sponsored_id) + begin_sponsoring_future_reserves_op = Xdr.types.BeginSponsoringFutureReservesOp( + sponsoredID=sponsored_id + ) body = Xdr.nullclass() body.type = Xdr.const.BEGIN_SPONSORING_FUTURE_RESERVES body.beginSponsoringFutureReservesOp = begin_sponsoring_future_reserves_op @@ -25,7 +27,7 @@ def _to_operation_body(self) -> Xdr.nullclass: @classmethod def from_xdr_object( - cls, operation_xdr_object: Xdr.types.Operation + cls, operation_xdr_object: Xdr.types.Operation ) -> "BeginSponsoringFutureReserves": """Creates a :class:`BeginSponsoringFutureReserves` object from an XDR Operation object. diff --git a/stellar_sdk/operation/end_sponsoring_future_reserves.py b/stellar_sdk/operation/end_sponsoring_future_reserves.py index 70f699b9..2da1a6b2 100644 --- a/stellar_sdk/operation/end_sponsoring_future_reserves.py +++ b/stellar_sdk/operation/end_sponsoring_future_reserves.py @@ -17,12 +17,12 @@ def _to_operation_body(self) -> Xdr.nullclass: @classmethod def from_xdr_object( - cls, operation_xdr_object: Xdr.types.Operation + cls, operation_xdr_object: Xdr.types.Operation ) -> "EndSponsoringFutureReserves": """Creates a :class:`EndSponsoringFutureReserves` object from an XDR Operation object. """ source = Operation.get_source_from_xdr_obj(operation_xdr_object) - op = cls(source=source, ) + op = cls(source=source,) op._source_muxed = Operation.get_source_muxed_from_xdr_obj(operation_xdr_object) return op diff --git a/stellar_sdk/operation/revoke_sponsorship.py b/stellar_sdk/operation/revoke_sponsorship.py index 51c9ea6a..71273c5b 100644 --- a/stellar_sdk/operation/revoke_sponsorship.py +++ b/stellar_sdk/operation/revoke_sponsorship.py @@ -1,14 +1,20 @@ import binascii from enum import IntEnum +from typing import Optional from .operation import Operation from ..asset import Asset from ..keypair import Keypair -from ..signer import Signer as XDRSigner +from ..signer_key import SignerKey +from ..strkey import StrKey from ..xdr import Xdr +from ..exceptions import ValueError class RevokeSponsorshipType(IntEnum): + """Currently supported RevokeSponsorship types. + """ + ACCOUNT = 0 TRUSTLINE = 1 OFFER = 2 @@ -18,54 +24,146 @@ class RevokeSponsorshipType(IntEnum): class TrustLine: - def __init__(self, account_id: str, asset: Asset): + def __init__(self, account_id: str, asset: Asset) -> None: self.account_id = account_id self.asset = asset class Offer: - def __init__(self, seller_id: str, offer_id: int): + def __init__(self, seller_id: str, offer_id: int) -> None: self.seller_id = seller_id self.offer_id = offer_id class Data: - def __init__(self, account_id: str, data_name: str): + def __init__(self, account_id: str, data_name: str) -> None: self.account_id = account_id self.data_name = data_name class Signer: - def __init__(self, account_id: str, signer_key: XDRSigner): + def __init__(self, account_id: str, signer_key: SignerKey) -> None: self.account_id = account_id self.signer_key = signer_key class RevokeSponsorship(Operation): - def __init__(self, - revoke_sponsorship_type: RevokeSponsorshipType, - account_id: str, - trustline: TrustLine, - offer: Offer, - data: Data, - claimable_balance_id: str, - signer: Signer, - source: str = None): + def __init__( + self, + revoke_sponsorship_type: RevokeSponsorshipType, + account_id: Optional[str], + trustline: Optional[TrustLine], + offer: Optional[Offer], + data: Optional[Data], + claimable_balance_id: Optional[str], + signer: Optional[Signer], + source: str = None, + ) -> None: super().__init__(source) self.revoke_sponsorship_type = revoke_sponsorship_type self.account_id = account_id self.trustline = trustline self.offer = offer self.data = data - if isinstance(claimable_balance_id, str): - claimable_balance_id = binascii.unhexlify(claimable_balance_id) - self.claimable_balance_id: bytes = claimable_balance_id + self.claimable_balance_id = claimable_balance_id self.signer = signer @classmethod def type_code(cls) -> int: return Xdr.const.REVOKE_SPONSORSHIP + @classmethod + def revoke_account_sponsorship(cls, account_id: str, source: str = None): + return cls( + revoke_sponsorship_type=RevokeSponsorshipType.ACCOUNT, + account_id=account_id, + trustline=None, + offer=None, + data=None, + claimable_balance_id=None, + signer=None, + source=source, + ) + + @classmethod + def revoke_trustline_sponsorship( + cls, account_id: str, asset: Asset, source: str = None + ): + trustline = TrustLine(account_id=account_id, asset=asset) + return cls( + revoke_sponsorship_type=RevokeSponsorshipType.TRUSTLINE, + account_id=None, + trustline=trustline, + offer=None, + data=None, + claimable_balance_id=None, + signer=None, + source=source, + ) + + @classmethod + def revoke_offer_sponsorship( + cls, seller_id: str, offer_id: int, source: str = None + ): + offer = Offer(seller_id=seller_id, offer_id=offer_id) + return cls( + revoke_sponsorship_type=RevokeSponsorshipType.OFFER, + account_id=None, + trustline=None, + offer=offer, + data=None, + claimable_balance_id=None, + signer=None, + source=source, + ) + + @classmethod + def revoke_data_sponsorship( + cls, account_id: str, data_name: str, source: str = None + ): + data = Data(account_id=account_id, data_name=data_name) + return cls( + revoke_sponsorship_type=RevokeSponsorshipType.DATA, + account_id=None, + trustline=None, + offer=None, + data=data, + claimable_balance_id=None, + signer=None, + source=source, + ) + + @classmethod + def revoke_claimable_balance_sponsorship( + cls, claimable_balance_id: str, source: str = None + ): + return cls( + revoke_sponsorship_type=RevokeSponsorshipType.CLAIMABLE_BALANCE, + account_id=None, + trustline=None, + offer=None, + data=None, + claimable_balance_id=claimable_balance_id, + signer=None, + source=source, + ) + + @classmethod + def revoke_signer_sponsorship( + cls, account_id: str, signer_key: SignerKey, source: str = None + ): + signer = Signer(account_id=account_id, signer_key=signer_key) + return cls( + revoke_sponsorship_type=RevokeSponsorshipType.SIGNER, + account_id=None, + trustline=None, + offer=None, + data=None, + claimable_balance_id=None, + signer=signer, + source=source, + ) + def _to_operation_body(self) -> Xdr.nullclass: body = Xdr.nullclass() body.type = Xdr.const.REVOKE_SPONSORSHIP @@ -73,7 +171,9 @@ def _to_operation_body(self) -> Xdr.nullclass: ledger_key = Xdr.nullclass() ledger_key.type = Xdr.const.ACCOUNT account = Xdr.nullclass() - account.accountID = Keypair.from_public_key(self.account_id).xdr_account_id() + account.accountID = Keypair.from_public_key( + self.account_id + ).xdr_account_id() ledger_key.account = account revoke_sponsorship_op = Xdr.nullclass() revoke_sponsorship_op.type = Xdr.const.REVOKE_SPONSORSHIP_LEDGER_ENTRY @@ -84,7 +184,9 @@ def _to_operation_body(self) -> Xdr.nullclass: ledger_key = Xdr.nullclass() ledger_key.type = Xdr.const.TRUSTLINE trust_line = Xdr.nullclass() - trust_line.accountID = Keypair.from_public_key(self.trustline.account_id).xdr_account_id() + trust_line.accountID = Keypair.from_public_key( + self.trustline.account_id + ).xdr_account_id() trust_line.asset = self.trustline.asset.to_xdr_object() ledger_key.trustLine = trust_line revoke_sponsorship_op = Xdr.nullclass() @@ -96,7 +198,9 @@ def _to_operation_body(self) -> Xdr.nullclass: ledger_key = Xdr.nullclass() ledger_key.type = Xdr.const.OFFER offer = Xdr.nullclass() - offer.sellerID = Keypair.from_public_key(self.offer.seller_id).xdr_account_id() + offer.sellerID = Keypair.from_public_key( + self.offer.seller_id + ).xdr_account_id() offer.offerID = self.offer.offer_id ledger_key.offer = offer revoke_sponsorship_op = Xdr.nullclass() @@ -108,9 +212,11 @@ def _to_operation_body(self) -> Xdr.nullclass: ledger_key = Xdr.nullclass() ledger_key.type = Xdr.const.DATA data = Xdr.nullclass() - data.accountID = Keypair.from_public_key(self.data.account_id).xdr_account_id() - data.dataName = self.data.data_name - ledger_key.account = data + data.accountID = Keypair.from_public_key( + self.data.account_id + ).xdr_account_id() + data.dataName = self.data.data_name.encode() + ledger_key.data = data revoke_sponsorship_op = Xdr.nullclass() revoke_sponsorship_op.type = Xdr.const.REVOKE_SPONSORSHIP_LEDGER_ENTRY revoke_sponsorship_op.ledgerKey = ledger_key @@ -119,8 +225,12 @@ def _to_operation_body(self) -> Xdr.nullclass: elif self.revoke_sponsorship_type == RevokeSponsorshipType.CLAIMABLE_BALANCE: ledger_key = Xdr.nullclass() ledger_key.type = Xdr.const.CLAIMABLE_BALANCE + claimable_balance_bytes = binascii.unhexlify(self.claimable_balance_id) claimable_balance = Xdr.nullclass() - claimable_balance.accountID = Keypair.from_public_key(self.data.account_id).xdr_account_id() + balance_id = Xdr.nullclass() + balance_id.type = Xdr.const.CLAIMABLE_BALANCE_ID_TYPE_V0 # int32 + balance_id.v0 = claimable_balance_bytes[4:] + claimable_balance.balanceID = balance_id ledger_key.claimableBalance = claimable_balance revoke_sponsorship_op = Xdr.nullclass() revoke_sponsorship_op.type = Xdr.const.REVOKE_SPONSORSHIP_LEDGER_ENTRY @@ -129,11 +239,72 @@ def _to_operation_body(self) -> Xdr.nullclass: return body elif self.revoke_sponsorship_type == RevokeSponsorshipType.SIGNER: signer = Xdr.nullclass() - signer.accountID = Keypair.from_public_key(self.signer.account_id).xdr_account_id() + signer.accountID = Keypair.from_public_key( + self.signer.account_id + ).xdr_account_id() signer.signerKey = self.signer.signer_key.to_xdr_object() revoke_sponsorship_op = Xdr.nullclass() revoke_sponsorship_op.type = Xdr.const.REVOKE_SPONSORSHIP_SIGNER revoke_sponsorship_op.signer = signer body.revokeSponsorshipOp = revoke_sponsorship_op + return body else: - raise ValueError + raise ValueError( + f"{self.revoke_sponsorship_type} is not a valid RevokeSponsorshipType." + ) + + @classmethod + def from_xdr_object( + cls, operation_xdr_object: Xdr.types.Operation + ) -> "RevokeSponsorship": + """Creates a :class:`RevokeSponsorship` object from an XDR Operation + object. + """ + source = Operation.get_source_from_xdr_obj(operation_xdr_object) + op_type = operation_xdr_object.body.revokeSponsorshipOp.type + if op_type == Xdr.const.REVOKE_SPONSORSHIP_LEDGER_ENTRY: + ledger_key = operation_xdr_object.body.revokeSponsorshipOp.ledgerKey + ledger_key_type = ledger_key.type + if ledger_key_type == Xdr.const.ACCOUNT: + account_id = StrKey.encode_ed25519_public_key( + ledger_key.account.accountID.ed25519 + ) + op = cls.revoke_account_sponsorship(account_id, source) + elif ledger_key_type == Xdr.const.TRUSTLINE: + account_id = StrKey.encode_ed25519_public_key( + ledger_key.trustLine.accountID.ed25519 + ) + asset = Asset.from_xdr_object(ledger_key.trustLine.asset) + op = cls.revoke_trustline_sponsorship(account_id, asset, source) + elif ledger_key_type == Xdr.const.OFFER: + seller_id = StrKey.encode_ed25519_public_key( + ledger_key.offer.sellerID.ed25519 + ) + offer_id = ledger_key.offer.offerID + op = cls.revoke_offer_sponsorship(seller_id, offer_id, source) + elif ledger_key_type == Xdr.const.DATA: + account_id = StrKey.encode_ed25519_public_key( + ledger_key.data.accountID.ed25519 + ) + data_name = ledger_key.data.dataName.decode() + op = cls.revoke_data_sponsorship(account_id, data_name, source) + elif ledger_key_type == Xdr.const.CLAIMABLE_BALANCE: + balance_id = b"\x00" * 4 + ledger_key.claimableBalance.balanceID.v0 + balance_id = binascii.hexlify(balance_id).decode() + op = cls.revoke_claimable_balance_sponsorship(balance_id, source) + else: + raise ValueError + + elif op_type == Xdr.const.REVOKE_SPONSORSHIP_SIGNER: + account_id = StrKey.encode_ed25519_public_key( + operation_xdr_object.body.revokeSponsorshipOp.signer.accountID.ed25519 + ) + signer_key = SignerKey.from_xdr_object( + operation_xdr_object.body.revokeSponsorshipOp.signer.signerKey + ) + return cls.revoke_signer_sponsorship(account_id, signer_key, source) + else: + pass + + op._source_muxed = Operation.get_source_muxed_from_xdr_obj(operation_xdr_object) + return op diff --git a/stellar_sdk/signer.py b/stellar_sdk/signer.py index c2888575..e94ec2ff 100644 --- a/stellar_sdk/signer.py +++ b/stellar_sdk/signer.py @@ -1,7 +1,5 @@ -from .__version__ import __issues__ -from .exceptions import ValueError -from .strkey import StrKey from .xdr import Xdr +from .signer_key import SignerKey __all__ = ["Signer"] @@ -9,11 +7,11 @@ class Signer: """The :class:`Signer` object, which represents an account signer on Stellar's network. - :param signer_key: The XDR signer object - :param weight: + :param signer_key: The signer object + :param weight: The weight of the key """ - def __init__(self, signer_key: Xdr.types.SignerKey, weight) -> "None": + def __init__(self, signer_key: SignerKey, weight) -> "None": self.signer_key: Xdr.types.SignerKey = signer_key self.weight: int = weight @@ -28,11 +26,7 @@ def ed25519_public_key(cls, account_id: str, weight: int) -> "Signer": :exc:`Ed25519PublicKeyInvalidError `: if ``account_id`` is not a valid ed25519 public key. """ - signer_key = Xdr.types.SignerKey( - Xdr.const.SIGNER_KEY_TYPE_ED25519, - ed25519=StrKey.decode_ed25519_public_key(account_id), - ) - + signer_key = SignerKey.ed25519_public_key(account_id) return cls(signer_key, weight) @classmethod @@ -44,10 +38,7 @@ def pre_auth_tx(cls, pre_auth_tx_hash: bytes, weight: int) -> "Signer": :param weight: The weight of the signer (0 to delete or 1-255) :return: Pre AUTH TX Signer """ - signer_key = Xdr.types.SignerKey( - Xdr.const.SIGNER_KEY_TYPE_PRE_AUTH_TX, preAuthTx=pre_auth_tx_hash - ) - + signer_key = SignerKey.pre_auth_tx(pre_auth_tx_hash) return cls(signer_key, weight) @classmethod @@ -59,9 +50,7 @@ def sha256_hash(cls, sha256_hash: bytes, weight: int) -> "Signer": :param weight: The weight of the signer (0 to delete or 1-255) :return: SHA256 HASH Signer """ - signer_key = Xdr.types.SignerKey( - Xdr.const.SIGNER_KEY_TYPE_HASH_X, hashX=sha256_hash - ) + signer_key = SignerKey.sha256_hash(sha256_hash) return cls(signer_key, weight) def to_xdr_object(self) -> Xdr.types.Signer: @@ -73,23 +62,14 @@ def to_xdr_object(self) -> Xdr.types.Signer: @classmethod def from_xdr_object(cls, signer_xdr_object: Xdr.types.Signer) -> "Signer": - """Create a :class:`Signer` from an XDR TimeBounds object. + """Create a :class:`Signer` from an XDR Signer object. :param signer_xdr_object: The XDR Signer object. :return: A new :class:`Signer` object from the given XDR Signer object. """ weight = signer_xdr_object.weight - if signer_xdr_object.type == Xdr.const.SIGNER_KEY_TYPE_ED25519: - account_id = StrKey.encode_ed25519_public_key(signer_xdr_object.ed25519) - return cls.ed25519_public_key(account_id, weight) - elif signer_xdr_object.type == Xdr.const.SIGNER_KEY_TYPE_PRE_AUTH_TX: - return cls.pre_auth_tx(signer_xdr_object.preAuthTx, weight) - elif signer_xdr_object.type == Xdr.const.SIGNER_KEY_TYPE_HASH_X: - return cls.sha256_hash(signer_xdr_object.hashX, weight) - else: - raise ValueError( - f"This is an unknown signer type, please consider creating an issuer at {__issues__}." - ) + signer_key = SignerKey.from_xdr_object(signer_xdr_object.key) + return cls(signer_key, weight) def __eq__(self, other: object) -> bool: if not isinstance(other, self.__class__): diff --git a/stellar_sdk/signer_key.py b/stellar_sdk/signer_key.py new file mode 100644 index 00000000..07f1d683 --- /dev/null +++ b/stellar_sdk/signer_key.py @@ -0,0 +1,91 @@ +from .__version__ import __issues__ +from .exceptions import ValueError +from .strkey import StrKey +from .xdr import Xdr + +__all__ = ["SignerKey"] + + +class SignerKey: + """The :class:`SignerKey` object, which represents an account signer key on Stellar's network. + + :param signer_key: The XDR signer object + """ + + def __init__(self, signer_key: Xdr.types.SignerKey) -> "None": + self.signer_key: Xdr.types.SignerKey = signer_key + + @classmethod + def ed25519_public_key(cls, account_id: str) -> "SignerKey": + """Create ED25519 PUBLIC KEY Signer from account id. + + :param account_id: account id + :return: ED25519 PUBLIC KEY Signer + :raises: + :exc:`Ed25519PublicKeyInvalidError `: if ``account_id`` + is not a valid ed25519 public key. + """ + signer_key = Xdr.types.SignerKey( + Xdr.const.SIGNER_KEY_TYPE_ED25519, + ed25519=StrKey.decode_ed25519_public_key(account_id), + ) + + return cls(signer_key) + + @classmethod + def pre_auth_tx(cls, pre_auth_tx_hash: bytes) -> "SignerKey": + """Create Pre AUTH TX Signer from the sha256 hash of a transaction, + click `here `__ for more information. + + :param pre_auth_tx_hash: The sha256 hash of a transaction. + :return: Pre AUTH TX Signer + """ + signer_key = Xdr.types.SignerKey( + Xdr.const.SIGNER_KEY_TYPE_PRE_AUTH_TX, preAuthTx=pre_auth_tx_hash + ) + + return cls(signer_key) + + @classmethod + def sha256_hash(cls, sha256_hash: bytes) -> "SignerKey": + """Create SHA256 HASH Signer from a sha256 hash of a preimage, + click `here `__ for more information. + + :param sha256_hash: a sha256 hash of a preimage + :return: SHA256 HASH Signer + """ + signer_key = Xdr.types.SignerKey( + Xdr.const.SIGNER_KEY_TYPE_HASH_X, hashX=sha256_hash + ) + return cls(signer_key) + + def to_xdr_object(self) -> Xdr.types.SignerKey: + """Returns the xdr object for this SignerKey object. + + :return: XDR Signer object + """ + return self.signer_key + + @classmethod + def from_xdr_object(cls, signer_xdr_object: Xdr.types.Signer) -> "SignerKey": + """Create a :class:`SignerKey` from an XDR SignerKey object. + + :param signer_xdr_object: The XDR SignerKey object. + :return: A new :class:`SignerKey` object from the given XDR SignerKey object. + """ + if signer_xdr_object.type == Xdr.const.SIGNER_KEY_TYPE_ED25519: + account_id = StrKey.encode_ed25519_public_key(signer_xdr_object.ed25519) + return cls.ed25519_public_key(account_id) + elif signer_xdr_object.type == Xdr.const.SIGNER_KEY_TYPE_PRE_AUTH_TX: + return cls.pre_auth_tx(signer_xdr_object.preAuthTx) + elif signer_xdr_object.type == Xdr.const.SIGNER_KEY_TYPE_HASH_X: + return cls.sha256_hash(signer_xdr_object.hashX) + else: + raise ValueError( + f"This is an unknown signer type, please consider creating an issuer at {__issues__}." + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, self.__class__): + return NotImplemented # pragma: no cover + return self.to_xdr_object().to_xdr() == other.to_xdr_object().to_xdr() diff --git a/tests/test_operation.py b/tests/test_operation.py index 11d08a19..77b1188d 100644 --- a/tests/test_operation.py +++ b/tests/test_operation.py @@ -7,9 +7,15 @@ from stellar_sdk.operation import Operation, CreateAccount from stellar_sdk.operation.account_merge import AccountMerge from stellar_sdk.operation.allow_trust import AllowTrust, TrustLineEntryFlag +from stellar_sdk.operation.begin_sponsoring_future_reserves import ( + BeginSponsoringFutureReserves, +) from stellar_sdk.operation.bump_sequence import BumpSequence from stellar_sdk.operation.change_trust import ChangeTrust from stellar_sdk.operation.create_passive_sell_offer import CreatePassiveSellOffer +from stellar_sdk.operation.end_sponsoring_future_reserves import ( + EndSponsoringFutureReserves, +) from stellar_sdk.operation.inflation import Inflation from stellar_sdk.operation.manage_buy_offer import ManageBuyOffer from stellar_sdk.operation.manage_data import ManageData @@ -19,6 +25,7 @@ from stellar_sdk.operation.path_payment_strict_send import PathPaymentStrictSend from stellar_sdk.operation.payment import Payment from stellar_sdk.operation.set_options import SetOptions, Flag +from stellar_sdk.operation.revoke_sponsorship import RevokeSponsorship from stellar_sdk.operation.utils import ( check_price, check_amount, @@ -27,6 +34,7 @@ check_ed25519_public_key, ) from stellar_sdk.signer import Signer +from stellar_sdk.signer_key import SignerKey from stellar_sdk.utils import sha256 @@ -1212,3 +1220,131 @@ def test_check_asset_code(self, asset_code): def test_check_asset_code_raise(self, asset_code): with pytest.raises(AssetCodeInvalidError, match="Asset code is invalid"): check_asset_code(asset_code) + + +class TestBeginSponsoringFutureReserves: + def test_xdr(self): + source = "GDL635DMMORJHKEHHQIIB4VPYM6YGEMPLORYHHM2DEHAUOUXLSTMHQDV" + sponsored_id = "GB2DRLHCWHUCB2BS4IRRY2GBQKVAKEXOU2EMTMLSUOXVNMZY7W6BSGZ7" + xdr = "AAAAAQAAAADX7fRsY6KTqIc8EIDyr8M9gxGPW6ODnZoZDgo6l1ymwwAAABAAAAAAdDis4rHoIOgy4iMcaMGCqgUS7qaIybFyo69Wszj9vBk=" + op = BeginSponsoringFutureReserves(sponsored_id, source) + assert op.to_xdr_object().to_xdr() == xdr + assert ( + Operation.from_xdr_object(op.to_xdr_object()).to_xdr_object().to_xdr() + == xdr + ) + + def test_xdr_no_source(self): + source = None + sponsored_id = "GB2DRLHCWHUCB2BS4IRRY2GBQKVAKEXOU2EMTMLSUOXVNMZY7W6BSGZ7" + xdr = "AAAAAAAAABAAAAAAdDis4rHoIOgy4iMcaMGCqgUS7qaIybFyo69Wszj9vBk=" + op = BeginSponsoringFutureReserves(sponsored_id, source) + assert op.to_xdr_object().to_xdr() == xdr + assert ( + Operation.from_xdr_object(op.to_xdr_object()).to_xdr_object().to_xdr() + == xdr + ) + + +class TestEndSponsoringFutureReserves: + def test_xdr(self): + source = "GDL635DMMORJHKEHHQIIB4VPYM6YGEMPLORYHHM2DEHAUOUXLSTMHQDV" + xdr = "AAAAAQAAAADX7fRsY6KTqIc8EIDyr8M9gxGPW6ODnZoZDgo6l1ymwwAAABE=" + op = EndSponsoringFutureReserves(source) + assert op.to_xdr_object().to_xdr() == xdr + assert ( + Operation.from_xdr_object(op.to_xdr_object()).to_xdr_object().to_xdr() + == xdr + ) + + def test_xdr_no_source(self): + source = None + xdr = "AAAAAAAAABE=" + op = EndSponsoringFutureReserves(source) + assert op.to_xdr_object().to_xdr() == xdr + assert ( + Operation.from_xdr_object(op.to_xdr_object()).to_xdr_object().to_xdr() + == xdr + ) + + +class TestRevokeSponsorship: + def test_account_xdr(self): + source = "GDL635DMMORJHKEHHQIIB4VPYM6YGEMPLORYHHM2DEHAUOUXLSTMHQDV" + account_id = "GB2DRLHCWHUCB2BS4IRRY2GBQKVAKEXOU2EMTMLSUOXVNMZY7W6BSGZ7" + xdr = "AAAAAQAAAADX7fRsY6KTqIc8EIDyr8M9gxGPW6ODnZoZDgo6l1ymwwAAABIAAAAAAAAAAAAAAAB0OKzisegg6DLiIxxowYKqBRLupojJsXKjr1azOP28GQ==" + + op = RevokeSponsorship.revoke_account_sponsorship(account_id, source) + assert op.to_xdr_object().to_xdr() == xdr + assert ( + Operation.from_xdr_object(op.to_xdr_object()).to_xdr_object().to_xdr() + == xdr + ) + + def test_trustline_xdr(self): + source = "GDL635DMMORJHKEHHQIIB4VPYM6YGEMPLORYHHM2DEHAUOUXLSTMHQDV" + account_id = "GB2DRLHCWHUCB2BS4IRRY2GBQKVAKEXOU2EMTMLSUOXVNMZY7W6BSGZ7" + asset = Asset("CAT", "GCEYOF66NL73LL6RIPSIP34WOCESQ3GKJOAYXOEVNKRWRNQRYUILCQWC") + xdr = "AAAAAQAAAADX7fRsY6KTqIc8EIDyr8M9gxGPW6ODnZoZDgo6l1ymwwAAABIAAAAAAAAAAQAAAAB0OKzisegg6DLiIxxowYKqBRLupojJsXKjr1azOP28GQAAAAFDQVQAAAAAAImHF95q/7Wv0UPkh++WcIkobMpLgYu4lWqjaLYRxRCx" + + op = RevokeSponsorship.revoke_trustline_sponsorship(account_id, asset, source) + assert op.to_xdr_object().to_xdr() == xdr + assert ( + Operation.from_xdr_object(op.to_xdr_object()).to_xdr_object().to_xdr() + == xdr + ) + + def test_offer_xdr(self): + source = "GDL635DMMORJHKEHHQIIB4VPYM6YGEMPLORYHHM2DEHAUOUXLSTMHQDV" + seller_id = "GB2DRLHCWHUCB2BS4IRRY2GBQKVAKEXOU2EMTMLSUOXVNMZY7W6BSGZ7" + offer_id = 12345 + xdr = "AAAAAQAAAADX7fRsY6KTqIc8EIDyr8M9gxGPW6ODnZoZDgo6l1ymwwAAABIAAAAAAAAAAgAAAAB0OKzisegg6DLiIxxowYKqBRLupojJsXKjr1azOP28GQAAAAAAADA5" + + op = RevokeSponsorship.revoke_offer_sponsorship(seller_id, offer_id, source) + assert op.to_xdr_object().to_xdr() == xdr + assert ( + Operation.from_xdr_object(op.to_xdr_object()).to_xdr_object().to_xdr() + == xdr + ) + + def test_date_xdr(self): + source = "GDL635DMMORJHKEHHQIIB4VPYM6YGEMPLORYHHM2DEHAUOUXLSTMHQDV" + account_id = "GB2DRLHCWHUCB2BS4IRRY2GBQKVAKEXOU2EMTMLSUOXVNMZY7W6BSGZ7" + data_name = "Stellar Python SDK" + xdr = "AAAAAQAAAADX7fRsY6KTqIc8EIDyr8M9gxGPW6ODnZoZDgo6l1ymwwAAABIAAAAAAAAAAwAAAAB0OKzisegg6DLiIxxowYKqBRLupojJsXKjr1azOP28GQAAABJTdGVsbGFyIFB5dGhvbiBTREsAAA==" + + op = RevokeSponsorship.revoke_data_sponsorship(account_id, data_name, source) + assert op.to_xdr_object().to_xdr() == xdr + assert ( + Operation.from_xdr_object(op.to_xdr_object()).to_xdr_object().to_xdr() + == xdr + ) + + def test_claimable_balance_id_xdr(self): + source = "GDL635DMMORJHKEHHQIIB4VPYM6YGEMPLORYHHM2DEHAUOUXLSTMHQDV" + balance_id = ( + "00000000da0d57da7d4850e7fc10d2a9d0ebc731f7afb40574c03395b17d49149b91f5be" + ) + xdr = "AAAAAQAAAADX7fRsY6KTqIc8EIDyr8M9gxGPW6ODnZoZDgo6l1ymwwAAABIAAAAAAAAABAAAAADaDVfafUhQ5/wQ0qnQ68cx96+0BXTAM5WxfUkUm5H1vg==" + + op = RevokeSponsorship.revoke_claimable_balance_sponsorship(balance_id, source) + assert op.to_xdr_object().to_xdr() == xdr + assert ( + Operation.from_xdr_object(op.to_xdr_object()).to_xdr_object().to_xdr() + == xdr + ) + + def test_signer_xdr(self): + source = "GDL635DMMORJHKEHHQIIB4VPYM6YGEMPLORYHHM2DEHAUOUXLSTMHQDV" + account_id = "GB2DRLHCWHUCB2BS4IRRY2GBQKVAKEXOU2EMTMLSUOXVNMZY7W6BSGZ7" + signer_key = SignerKey.ed25519_public_key( + "GCEYOF66NL73LL6RIPSIP34WOCESQ3GKJOAYXOEVNKRWRNQRYUILCQWC" + ) + xdr = "AAAAAQAAAADX7fRsY6KTqIc8EIDyr8M9gxGPW6ODnZoZDgo6l1ymwwAAABIAAAABAAAAAHQ4rOKx6CDoMuIjHGjBgqoFEu6miMmxcqOvVrM4/bwZAAAAAImHF95q/7Wv0UPkh++WcIkobMpLgYu4lWqjaLYRxRCx" + + op = RevokeSponsorship.revoke_signer_sponsorship(account_id, signer_key, source) + assert op.to_xdr_object().to_xdr() == xdr + assert ( + Operation.from_xdr_object(op.to_xdr_object()).to_xdr_object().to_xdr() + == xdr + ) From 2a1118677ad5f14fa537c94dc6a6477bf67f467b Mon Sep 17 00:00:00 2001 From: overcat <4catcode@gmail.com> Date: Wed, 30 Sep 2020 17:40:26 +0800 Subject: [PATCH 06/12] WIP --- stellar_sdk/signer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stellar_sdk/signer.py b/stellar_sdk/signer.py index e94ec2ff..fdce5a32 100644 --- a/stellar_sdk/signer.py +++ b/stellar_sdk/signer.py @@ -12,7 +12,7 @@ class Signer: """ def __init__(self, signer_key: SignerKey, weight) -> "None": - self.signer_key: Xdr.types.SignerKey = signer_key + self.signer_key: SignerKey = signer_key self.weight: int = weight @classmethod @@ -58,7 +58,7 @@ def to_xdr_object(self) -> Xdr.types.Signer: :return: XDR Signer object """ - return Xdr.types.Signer(self.signer_key, self.weight) + return Xdr.types.Signer(self.signer_key.to_xdr_object(), self.weight) @classmethod def from_xdr_object(cls, signer_xdr_object: Xdr.types.Signer) -> "Signer": From 0223f0405bde920ef3e028e5ad1aa6580bcbd8e7 Mon Sep 17 00:00:00 2001 From: overcat <4catcode@gmail.com> Date: Wed, 30 Sep 2020 17:45:12 +0800 Subject: [PATCH 07/12] WIP --- stellar_sdk/sep/txrep.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/stellar_sdk/sep/txrep.py b/stellar_sdk/sep/txrep.py index d2788771..011464ab 100644 --- a/stellar_sdk/sep/txrep.py +++ b/stellar_sdk/sep/txrep.py @@ -716,18 +716,18 @@ def add_signer(signer: Signer) -> None: add_body_line("signer._present", _false if signer is None else _true) if signer is None: return - if signer.signer_key.type == Xdr.const.SIGNER_KEY_TYPE_ED25519: + if signer.signer_key.signer_key.type == Xdr.const.SIGNER_KEY_TYPE_ED25519: add_body_line( "signer.key", - StrKey.encode_ed25519_public_key(signer.signer_key.ed25519), + StrKey.encode_ed25519_public_key(signer.signer_key.signer_key.ed25519), ) - if signer.signer_key.type == Xdr.const.SIGNER_KEY_TYPE_PRE_AUTH_TX: + if signer.signer_key.signer_key.type == Xdr.const.SIGNER_KEY_TYPE_PRE_AUTH_TX: add_body_line( - "signer.key", StrKey.encode_pre_auth_tx(signer.signer_key.preAuthTx) + "signer.key", StrKey.encode_pre_auth_tx(signer.signer_key.signer_key.preAuthTx) ) - if signer.signer_key.type == Xdr.const.SIGNER_KEY_TYPE_HASH_X: + if signer.signer_key.signer_key.type == Xdr.const.SIGNER_KEY_TYPE_HASH_X: add_body_line( - "signer.key", StrKey.encode_sha256_hash(signer.signer_key.hashX) + "signer.key", StrKey.encode_sha256_hash(signer.signer_key.signer_key.hashX) ) add_body_line("signer.weight", signer.weight) From 853beff1cee20ee741b78d24c19c3163242aeeba Mon Sep 17 00:00:00 2001 From: overcat <4catcode@gmail.com> Date: Wed, 30 Sep 2020 17:47:17 +0800 Subject: [PATCH 08/12] WIP --- docs/en/api.rst | 7 +++++++ docs/zh_CN/api.rst | 7 +++++++ stellar_sdk/__init__.py | 2 ++ 3 files changed, 16 insertions(+) diff --git a/docs/en/api.rst b/docs/en/api.rst index a914aea6..7d111845 100644 --- a/docs/en/api.rst +++ b/docs/en/api.rst @@ -446,6 +446,13 @@ Signer :members: :inherited-members: +SignerKey +^^^^^^^^^ + +.. autoclass:: stellar_sdk.signer_key.SignerKey + :members: + :inherited-members: + TimeBounds ^^^^^^^^^^ diff --git a/docs/zh_CN/api.rst b/docs/zh_CN/api.rst index f7e0b4ad..30a2b028 100644 --- a/docs/zh_CN/api.rst +++ b/docs/zh_CN/api.rst @@ -446,6 +446,13 @@ Signer :members: :inherited-members: +SignerKey +^^^^^^^^^ + +.. autoclass:: stellar_sdk.signer_key.SignerKey + :members: + :inherited-members: + TimeBounds ^^^^^^^^^^ diff --git a/stellar_sdk/__init__.py b/stellar_sdk/__init__.py index d3f64f3a..7e601168 100644 --- a/stellar_sdk/__init__.py +++ b/stellar_sdk/__init__.py @@ -21,6 +21,7 @@ from .price import Price from .server import Server from .signer import Signer +from .signer_key import SignerKey from .time_bounds import TimeBounds from .transaction import Transaction from .transaction_builder import TransactionBuilder @@ -53,6 +54,7 @@ "Price", "Server", "Signer", + "SignerKey", "TimeBounds", "Transaction", "TransactionBuilder", From f7a668efa05ad005d593ecb60c3bbd527ff1a863 Mon Sep 17 00:00:00 2001 From: overcat <4catcode@gmail.com> Date: Wed, 30 Sep 2020 18:26:40 +0800 Subject: [PATCH 09/12] WIP --- docs/en/api.rst | 15 +++++ docs/zh_CN/api.rst | 15 +++++ .../begin_sponsoring_future_reserves.py | 15 +++++ .../end_sponsoring_future_reserves.py | 15 +++++ stellar_sdk/operation/revoke_sponsorship.py | 57 +++++++++++++++++-- 5 files changed, 112 insertions(+), 5 deletions(-) diff --git a/docs/en/api.rst b/docs/en/api.rst index 7d111845..409dd4d2 100644 --- a/docs/en/api.rst +++ b/docs/en/api.rst @@ -425,6 +425,21 @@ SetOptions .. autoclass:: stellar_sdk.operation.set_options.Flag :members: +BeginSponsoringFutureReserves +----------------------------- +.. autoclass:: stellar_sdk.operation.BeginSponsoringFutureReserves + :members: to_xdr_object, from_xdr_object + +EndSponsoringFutureReserves +--------------------------- +.. autoclass:: stellar_sdk.operation.EndSponsoringFutureReserves + :members: to_xdr_object, from_xdr_object + +RevokeSponsorship +----------------- +.. autoclass:: stellar_sdk.operation.RevokeSponsorship + :members: to_xdr_object, from_xdr_object + Price ^^^^^ diff --git a/docs/zh_CN/api.rst b/docs/zh_CN/api.rst index 30a2b028..f1cde73b 100644 --- a/docs/zh_CN/api.rst +++ b/docs/zh_CN/api.rst @@ -425,6 +425,21 @@ SetOptions .. autoclass:: stellar_sdk.operation.set_options.Flag :members: +BeginSponsoringFutureReserves +----------------------------- +.. autoclass:: stellar_sdk.operation.BeginSponsoringFutureReserves + :members: to_xdr_object, from_xdr_object + +EndSponsoringFutureReserves +--------------------------- +.. autoclass:: stellar_sdk.operation.EndSponsoringFutureReserves + :members: to_xdr_object, from_xdr_object + +RevokeSponsorship +----------------- +.. autoclass:: stellar_sdk.operation.RevokeSponsorship + :members: to_xdr_object, from_xdr_object + Price ^^^^^ diff --git a/stellar_sdk/operation/begin_sponsoring_future_reserves.py b/stellar_sdk/operation/begin_sponsoring_future_reserves.py index dda3c244..39219e42 100644 --- a/stellar_sdk/operation/begin_sponsoring_future_reserves.py +++ b/stellar_sdk/operation/begin_sponsoring_future_reserves.py @@ -6,6 +6,21 @@ class BeginSponsoringFutureReserves(Operation): + """The :class:`BeginSponsoringFutureReserves` object, which represents a BeginSponsoringFutureReserves + operation on Stellar's network. + + Establishes the is-sponsoring-future-reserves-for relationship between the source account and sponsoredID. + See `Sponsored Reserves _` for more information. + + See `Begin Sponsoring Future Reserves + _`. + + Threshold: Medium + + :param sponsored_id: The sponsored account id. + :param source: The source account (defaults to transaction source). + """ + def __init__(self, sponsored_id: str, source: str = None) -> None: super().__init__(source) check_ed25519_public_key(sponsored_id) diff --git a/stellar_sdk/operation/end_sponsoring_future_reserves.py b/stellar_sdk/operation/end_sponsoring_future_reserves.py index 2da1a6b2..c37af365 100644 --- a/stellar_sdk/operation/end_sponsoring_future_reserves.py +++ b/stellar_sdk/operation/end_sponsoring_future_reserves.py @@ -3,6 +3,21 @@ class EndSponsoringFutureReserves(Operation): + """The :class:`EndSponsoringFutureReserves` object, which represents a EndSponsoringFutureReserves + operation on Stellar's network. + + Terminates the current is-sponsoring-future-reserves-for relationship in which the source account is sponsored. + See `Sponsored Reserves _` for more information. + + See `End Sponsoring Future Reserves + _`. + + Threshold: Medium + + :param sponsored_id: The sponsored account id. + :param source: The source account (defaults to transaction source). + """ + def __init__(self, source: str = None) -> None: super().__init__(source) diff --git a/stellar_sdk/operation/revoke_sponsorship.py b/stellar_sdk/operation/revoke_sponsorship.py index 71273c5b..db75d981 100644 --- a/stellar_sdk/operation/revoke_sponsorship.py +++ b/stellar_sdk/operation/revoke_sponsorship.py @@ -9,6 +9,7 @@ from ..strkey import StrKey from ..xdr import Xdr from ..exceptions import ValueError +from .utils import check_ed25519_public_key class RevokeSponsorshipType(IntEnum): @@ -25,29 +26,37 @@ class RevokeSponsorshipType(IntEnum): class TrustLine: def __init__(self, account_id: str, asset: Asset) -> None: + check_ed25519_public_key(account_id) self.account_id = account_id self.asset = asset class Offer: def __init__(self, seller_id: str, offer_id: int) -> None: + check_ed25519_public_key(seller_id) self.seller_id = seller_id self.offer_id = offer_id class Data: def __init__(self, account_id: str, data_name: str) -> None: + check_ed25519_public_key(account_id) self.account_id = account_id self.data_name = data_name class Signer: def __init__(self, account_id: str, signer_key: SignerKey) -> None: + check_ed25519_public_key(account_id) self.account_id = account_id self.signer_key = signer_key class RevokeSponsorship(Operation): + """ + + """ + def __init__( self, revoke_sponsorship_type: RevokeSponsorshipType, @@ -74,6 +83,12 @@ def type_code(cls) -> int: @classmethod def revoke_account_sponsorship(cls, account_id: str, source: str = None): + """Create a "revoke sponsorship" operation for an account. + + :param account_id: The sponsored account ID. + :param source: The source account (defaults to transaction source). + :return: A "revoke sponsorship" operation for an account. + """ return cls( revoke_sponsorship_type=RevokeSponsorshipType.ACCOUNT, account_id=account_id, @@ -89,6 +104,13 @@ def revoke_account_sponsorship(cls, account_id: str, source: str = None): def revoke_trustline_sponsorship( cls, account_id: str, asset: Asset, source: str = None ): + """Create a "revoke sponsorship" operation for a trustline. + + :param account_id: The account ID which owns the trustline. + :param asset: The asset in the trustline. + :param source: The source account (defaults to transaction source). + :return: A "revoke sponsorship" operation for a trustline. + """ trustline = TrustLine(account_id=account_id, asset=asset) return cls( revoke_sponsorship_type=RevokeSponsorshipType.TRUSTLINE, @@ -105,6 +127,13 @@ def revoke_trustline_sponsorship( def revoke_offer_sponsorship( cls, seller_id: str, offer_id: int, source: str = None ): + """Create a "revoke sponsorship" operation for an offer. + + :param seller_id: The account ID which created the offer. + :param offer_id: The offer ID. + :param source: The source account (defaults to transaction source). + :return: A "revoke sponsorship" operation for an offer. + """ offer = Offer(seller_id=seller_id, offer_id=offer_id) return cls( revoke_sponsorship_type=RevokeSponsorshipType.OFFER, @@ -121,6 +150,13 @@ def revoke_offer_sponsorship( def revoke_data_sponsorship( cls, account_id: str, data_name: str, source: str = None ): + """Create a "revoke sponsorship" operation for a data entry. + + :param account_id: The account ID which owns the data entry. + :param data_name: The name of the data entry + :param source: The source account (defaults to transaction source). + :return: A "revoke sponsorship" operation for a data entry. + """ data = Data(account_id=account_id, data_name=data_name) return cls( revoke_sponsorship_type=RevokeSponsorshipType.DATA, @@ -137,6 +173,12 @@ def revoke_data_sponsorship( def revoke_claimable_balance_sponsorship( cls, claimable_balance_id: str, source: str = None ): + """Create a "revoke sponsorship" operation for a claimable balance. + + :param claimable_balance_id: The sponsored claimable balance ID. + :param source: The source account (defaults to transaction source). + :return: A "revoke sponsorship" operation for a claimable balance. + """ return cls( revoke_sponsorship_type=RevokeSponsorshipType.CLAIMABLE_BALANCE, account_id=None, @@ -152,6 +194,13 @@ def revoke_claimable_balance_sponsorship( def revoke_signer_sponsorship( cls, account_id: str, signer_key: SignerKey, source: str = None ): + """Create a "revoke sponsorship" operation for a signer. + + :param account_id: The account ID where the signer sponsorship is being removed from. + :param signer_key: The signer whose sponsorship is being removed. + :param source: The source account (defaults to transaction source). + :return: A "revoke sponsorship" operation for a signer. + """ signer = Signer(account_id=account_id, signer_key=signer_key) return cls( revoke_sponsorship_type=RevokeSponsorshipType.SIGNER, @@ -293,8 +342,7 @@ def from_xdr_object( balance_id = binascii.hexlify(balance_id).decode() op = cls.revoke_claimable_balance_sponsorship(balance_id, source) else: - raise ValueError - + raise ValueError(f"{ledger_key_type} is an unsupported LedgerKey type.") elif op_type == Xdr.const.REVOKE_SPONSORSHIP_SIGNER: account_id = StrKey.encode_ed25519_public_key( operation_xdr_object.body.revokeSponsorshipOp.signer.accountID.ed25519 @@ -302,9 +350,8 @@ def from_xdr_object( signer_key = SignerKey.from_xdr_object( operation_xdr_object.body.revokeSponsorshipOp.signer.signerKey ) - return cls.revoke_signer_sponsorship(account_id, signer_key, source) + op = cls.revoke_signer_sponsorship(account_id, signer_key, source) else: - pass - + raise ValueError(f"{op_type} is an unsupported RevokeSponsorship type.") op._source_muxed = Operation.get_source_muxed_from_xdr_obj(operation_xdr_object) return op From b6e9ee9a115edca712ab09e3728ac73d489657cb Mon Sep 17 00:00:00 2001 From: overcat <4catcode@gmail.com> Date: Wed, 30 Sep 2020 18:55:33 +0800 Subject: [PATCH 10/12] WIP --- stellar_sdk/transaction_builder.py | 141 +++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/stellar_sdk/transaction_builder.py b/stellar_sdk/transaction_builder.py index 107da5d2..20068563 100644 --- a/stellar_sdk/transaction_builder.py +++ b/stellar_sdk/transaction_builder.py @@ -3,6 +3,7 @@ from decimal import Decimal from typing import List, Union, Optional +from . import SignerKey from .account import Account from .asset import Asset from .exceptions import ValueError @@ -828,3 +829,143 @@ def append_bump_sequence_op( """ op = BumpSequence(bump_to, source) return self.append_operation(op) + + def append_begin_sponsoring_future_reserves_op( + self, sponsored_id: str, source: str = None + ) -> "TransactionBuilder": + """Append a :class:`BeginSponsoringFutureReserves ` + operation to the list of operations. + + :param sponsored_id: The sponsored account id. + :param source: The source account (defaults to transaction source). + :return: This builder instance. + """ + op = BeginSponsoringFutureReserves(sponsored_id, source) + return self.append_operation(op) + + def append_end_sponsoring_future_reserves_op( + self, source: str = None + ) -> "TransactionBuilder": + """Append a :class:`EndSponsoringFutureReserves ` + operation to the list of operations. + + :param source: The source account (defaults to transaction source). + :return: This builder instance. + """ + op = EndSponsoringFutureReserves(source) + return self.append_operation(op) + + def append_revoke_account_sponsorship_op( + self, account_id: str, source: str = None + ) -> "TransactionBuilder": + """Append a :class:`EndSponsoringFutureReserves ` operation + for an account to the list of operations. + + :param account_id: The sponsored account ID. + :param source: The source account (defaults to transaction source). + :return: This builder instance. + """ + op = RevokeSponsorship.revoke_account_sponsorship(account_id, source) + return self.append_operation(op) + + def append_revoke_trustline_sponsorship_op( + self, account_id: str, asset: Asset, source: str = None + ) -> "TransactionBuilder": + """Append a :class:`EndSponsoringFutureReserves ` operation + for a trustline to the list of operations. + + :param account_id: The account ID which owns the trustline. + :param asset: The asset in the trustline. + :param source: The source account (defaults to transaction source). + :return: This builder instance. + """ + op = RevokeSponsorship.revoke_trustline_sponsorship(account_id, asset, source) + return self.append_operation(op) + + def append_revoke_offer_sponsorship_op( + self, seller_id: str, offer_id: int, source: str = None + ) -> "TransactionBuilder": + """Append a :class:`EndSponsoringFutureReserves ` operation + for an offer to the list of operations. + + :param seller_id: The account ID which created the offer. + :param offer_id: The offer ID. + :param source: The source account (defaults to transaction source). + :return: This builder instance. + """ + op = RevokeSponsorship.revoke_offer_sponsorship(seller_id, offer_id, source) + return self.append_operation(op) + + def append_revoke_data_sponsorship_op( + self, account_id: str, data_name: str, source: str = None + ) -> "TransactionBuilder": + """Append a :class:`EndSponsoringFutureReserves ` operation + for a data entry to the list of operations. + + :param account_id: The account ID which owns the data entry. + :param data_name: The name of the data entry + :param source: The source account (defaults to transaction source). + :return: This builder instance. + """ + op = RevokeSponsorship.revoke_data_sponsorship(account_id, data_name, source) + return self.append_operation(op) + + def append_revoke_claimable_balance_sponsorship_op( + self, claimable_balance_id: str, source: str = None + ) -> "TransactionBuilder": + """Append a :class:`EndSponsoringFutureReserves ` operation + for a claimable to the list of operations. + + :param claimable_balance_id: The sponsored claimable balance ID. + :param source: The source account (defaults to transaction source). + :return: This builder instance. + """ + op = RevokeSponsorship.revoke_claimable_balance_sponsorship( + claimable_balance_id, source + ) + return self.append_operation(op) + + def append_revoke_ed25519_public_key_signer_sponsorship_op( + self, account_id: str, signer_key: str, source: str = None + ) -> "TransactionBuilder": + """Append a :class:`EndSponsoringFutureReserves ` operation + for a ed25519_public_key signer to the list of operations. + + :param account_id: The account ID where the signer sponsorship is being removed from. + :param signer_key: The account id of the ed25519_public_key signer. + :param source: The source account (defaults to transaction source). + :return: This builder instance. + """ + signer_key = SignerKey.ed25519_public_key(signer_key) + op = RevokeSponsorship.revoke_signer_sponsorship(account_id, signer_key, source) + return self.append_operation(op) + + def append_revoke_hashx_signer_sponsorship_op( + self, account_id: str, signer_key: Union[bytes, str], source: str = None + ) -> "TransactionBuilder": + """Append a :class:`EndSponsoringFutureReserves ` operation + for a hashx signer to the list of operations. + + :param account_id: The account ID where the signer sponsorship is being removed from. + :param signer_key: The account id of the hashx signer. + :param source: The source account (defaults to transaction source). + :return: This builder instance. + """ + signer_key = SignerKey.sha256_hash(hex_to_bytes(signer_key)) + op = RevokeSponsorship.revoke_signer_sponsorship(account_id, signer_key, source) + return self.append_operation(op) + + def append_revoke_pre_auth_tx_signer_sponsorship_op( + self, account_id: str, signer_key: Union[bytes, str], source: str = None + ) -> "TransactionBuilder": + """Append a :class:`EndSponsoringFutureReserves ` operation + for a pre_auth_tx signer to the list of operations. + + :param account_id: The account ID where the signer sponsorship is being removed from. + :param signer_key: The account id of the pre_auth_tx signer. + :param source: The source account (defaults to transaction source). + :return: This builder instance. + """ + signer_key = SignerKey.pre_auth_tx(hex_to_bytes(signer_key)) + op = RevokeSponsorship.revoke_signer_sponsorship(account_id, signer_key, source) + return self.append_operation(op) From 25bc8c2d97bbcd792f434c5499bf4fac60eed72b Mon Sep 17 00:00:00 2001 From: overcat <4catcode@gmail.com> Date: Wed, 30 Sep 2020 23:00:03 +0800 Subject: [PATCH 11/12] WIP --- docs/en/api.rst | 15 ++++++++ docs/zh_CN/api.rst | 15 ++++++++ tests/test_transaction_builder.py | 59 +++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+) diff --git a/docs/en/api.rst b/docs/en/api.rst index 931ae040..18e99a19 100644 --- a/docs/en/api.rst +++ b/docs/en/api.rst @@ -459,6 +459,21 @@ RevokeSponsorship .. autoclass:: stellar_sdk.operation.RevokeSponsorship :members: to_xdr_object, from_xdr_object +.. autoclass:: stellar_sdk.operation.revoke_sponsorship.RevokeSponsorshipType + :members: + +.. autoclass:: stellar_sdk.operation.revoke_sponsorship.TrustLine + :members: + +.. autoclass:: stellar_sdk.operation.revoke_sponsorship.Offer + :members: + +.. autoclass:: stellar_sdk.operation.revoke_sponsorship.Data + :members: + +.. autoclass:: stellar_sdk.operation.revoke_sponsorship.Signer + :members: + Price ^^^^^ diff --git a/docs/zh_CN/api.rst b/docs/zh_CN/api.rst index 4c309b9c..1585c2c0 100644 --- a/docs/zh_CN/api.rst +++ b/docs/zh_CN/api.rst @@ -459,6 +459,21 @@ RevokeSponsorship .. autoclass:: stellar_sdk.operation.RevokeSponsorship :members: to_xdr_object, from_xdr_object +.. autoclass:: stellar_sdk.operation.revoke_sponsorship.RevokeSponsorshipType + :members: + +.. autoclass:: stellar_sdk.operation.revoke_sponsorship.TrustLine + :members: + +.. autoclass:: stellar_sdk.operation.revoke_sponsorship.Offer + :members: + +.. autoclass:: stellar_sdk.operation.revoke_sponsorship.Data + :members: + +.. autoclass:: stellar_sdk.operation.revoke_sponsorship.Signer + :members: + Price ^^^^^ diff --git a/tests/test_transaction_builder.py b/tests/test_transaction_builder.py index 457b7035..cd380184 100644 --- a/tests/test_transaction_builder.py +++ b/tests/test_transaction_builder.py @@ -413,3 +413,62 @@ def test_add_memo(self): source, Network.TESTNET_NETWORK_PASSPHRASE, base_fee=150 ).add_return_hash_memo(memo_hash) assert builder.memo == ReturnHashMemo(memo_hash) + + def test_to_xdr_sponsored_reserves(self): + sequence = 1 + source = Account( + "GDF5O4OWEMVBY5FLDHWA5RZTYSV2U276XGKZZ6VSHDDR3THSQ6OQS7UM", sequence + ) + builder = TransactionBuilder( + source, Network.TESTNET_NETWORK_PASSPHRASE, base_fee=150, v1=False + ) + builder.add_text_memo("Stellar Python SDK") + builder.add_time_bounds(1565590000, 1565600000) + op_source = "GDF5O4OWEMVBY5FLDHWA5RZTYSV2U276XGKZZ6VSHDDR3THSQ6OQS7UM" + op_account_id = "GCWWANEIF3Z4DMOE4LDRCS22HLLHOEQCOF3QKAC2XWTSYR2AEEQ3P5FW" + te = ( + builder.append_begin_sponsoring_future_reserves_op( + sponsored_id="GCEYOF66NL73LL6RIPSIP34WOCESQ3GKJOAYXOEVNKRWRNQRYUILCQWC", + source=op_source, + ) + .append_end_sponsoring_future_reserves_op(source=op_source) + .append_revoke_account_sponsorship_op( + account_id=op_account_id, source=op_source + ) + .append_revoke_trustline_sponsorship_op( + account_id=op_account_id, asset=Asset.native(), source=op_source + ) + .append_revoke_offer_sponsorship_op( + seller_id=op_account_id, offer_id=12315, source=op_source + ) + .append_revoke_data_sponsorship_op( + account_id=op_account_id, data_name="stellar", source=op_source + ) + .append_revoke_claimable_balance_sponsorship_op( + claimable_balance_id="00000000da0d57da7d4850e7fc10d2a9d0ebc731f7afb40574c03395b17d49149b91f5be", + source=op_source, + ) + .append_revoke_ed25519_public_key_signer_sponsorship_op( + account_id=op_account_id, + signer_key="GBWYVWA2PZBTRRBNZI55OG4EFDJSDNL6ASP2VAQKHORNUSSXP2NCV4N2", + source=op_source, + ) + .append_revoke_hashx_signer_sponsorship_op( + account_id=op_account_id, + signer_key="da0d57da7d4850e7fc10d2a9d0ebc731f7afb40574c03395b17d49149b91f5be", + source=op_source, + ) + .append_revoke_pre_auth_tx_signer_sponsorship_op( + account_id=op_account_id, + signer_key="da0d57da7d4850e7fc10d2a9d0ebc731f7afb40574c03395b17d49149b91f5be", + source=op_source, + ) + .build() + ) + + xdr = "AAAAAMvXcdYjKhx0qxnsDsczxKuqa/65lZz6sjjHHczyh50JAAAF3AAAAAAAAAACAAAAAQAAAABdUQHwAAAAAF1RKQAAAAABAAAAElN0ZWxsYXIgUHl0aG9uIFNESwAAAAAACgAAAAEAAAAAy9dx1iMqHHSrGewOxzPEq6pr/rmVnPqyOMcdzPKHnQkAAAAQAAAAAImHF95q/7Wv0UPkh++WcIkobMpLgYu4lWqjaLYRxRCxAAAAAQAAAADL13HWIyocdKsZ7A7HM8Srqmv+uZWc+rI4xx3M8oedCQAAABEAAAABAAAAAMvXcdYjKhx0qxnsDsczxKuqa/65lZz6sjjHHczyh50JAAAAEgAAAAAAAAAAAAAAAK1gNIgu88GxxOLHEUtaOtZ3EgJxdwUAWr2nLEdAISG3AAAAAQAAAADL13HWIyocdKsZ7A7HM8Srqmv+uZWc+rI4xx3M8oedCQAAABIAAAAAAAAAAQAAAACtYDSILvPBscTixxFLWjrWdxICcXcFAFq9pyxHQCEhtwAAAAAAAAABAAAAAMvXcdYjKhx0qxnsDsczxKuqa/65lZz6sjjHHczyh50JAAAAEgAAAAAAAAACAAAAAK1gNIgu88GxxOLHEUtaOtZ3EgJxdwUAWr2nLEdAISG3AAAAAAAAMBsAAAABAAAAAMvXcdYjKhx0qxnsDsczxKuqa/65lZz6sjjHHczyh50JAAAAEgAAAAAAAAADAAAAAK1gNIgu88GxxOLHEUtaOtZ3EgJxdwUAWr2nLEdAISG3AAAAB3N0ZWxsYXIAAAAAAQAAAADL13HWIyocdKsZ7A7HM8Srqmv+uZWc+rI4xx3M8oedCQAAABIAAAAAAAAABAAAAADaDVfafUhQ5/wQ0qnQ68cx96+0BXTAM5WxfUkUm5H1vgAAAAEAAAAAy9dx1iMqHHSrGewOxzPEq6pr/rmVnPqyOMcdzPKHnQkAAAASAAAAAQAAAACtYDSILvPBscTixxFLWjrWdxICcXcFAFq9pyxHQCEhtwAAAABtitgafkM4xC3KO9cbhCjTIbV+BJ+qggo7otpKV36aKgAAAAEAAAAAy9dx1iMqHHSrGewOxzPEq6pr/rmVnPqyOMcdzPKHnQkAAAASAAAAAQAAAACtYDSILvPBscTixxFLWjrWdxICcXcFAFq9pyxHQCEhtwAAAALaDVfafUhQ5/wQ0qnQ68cx96+0BXTAM5WxfUkUm5H1vgAAAAEAAAAAy9dx1iMqHHSrGewOxzPEq6pr/rmVnPqyOMcdzPKHnQkAAAASAAAAAQAAAACtYDSILvPBscTixxFLWjrWdxICcXcFAFq9pyxHQCEhtwAAAAHaDVfafUhQ5/wQ0qnQ68cx96+0BXTAM5WxfUkUm5H1vgAAAAAAAAAA" + assert te.to_xdr() == xdr + restore_te = TransactionBuilder.from_xdr( + xdr, Network.TESTNET_NETWORK_PASSPHRASE + ).build() + assert restore_te.to_xdr() == xdr From 685d3b17869f5d5b78423b9cb9e24235d4b94664 Mon Sep 17 00:00:00 2001 From: overcat <4catcode@gmail.com> Date: Thu, 1 Oct 2020 20:30:42 +0800 Subject: [PATCH 12/12] WIP --- stellar_sdk/operation/revoke_sponsorship.py | 36 ++++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/stellar_sdk/operation/revoke_sponsorship.py b/stellar_sdk/operation/revoke_sponsorship.py index db75d981..508455f9 100644 --- a/stellar_sdk/operation/revoke_sponsorship.py +++ b/stellar_sdk/operation/revoke_sponsorship.py @@ -1,3 +1,4 @@ +import base64 import binascii from enum import IntEnum from typing import Optional @@ -10,6 +11,7 @@ from ..xdr import Xdr from ..exceptions import ValueError from .utils import check_ed25519_public_key +from ..xdr.StellarXDR_type import ClaimableBalanceID class RevokeSponsorshipType(IntEnum): @@ -53,8 +55,30 @@ def __init__(self, account_id: str, signer_key: SignerKey) -> None: class RevokeSponsorship(Operation): - """ + """The :class:`RevokeSponsorship` object, which represents a RevokeSponsorship + operation on Stellar's network. + + The logic of this operation depends on the state of the source account. + + If the source account is not sponsored or is sponsored by the owner of the specified entry or sub-entry, + then attempt to revoke the sponsorship. If the source account is sponsored, the next step depends on whether the + entry is sponsored or not. If it is sponsored, attempt to transfer the sponsorship to the sponsor + of the source account. If the entry is not sponsored, then establish the sponsorship. + See `Sponsored Reserves _` for more information. + + See `Revoke Sponsorship + _`. + Threshold: Medium + + :param revoke_sponsorship_type: The sponsored account id. + :param account_id: The sponsored account ID. + :param trustline: The sponsored trustline. + :param offer: The sponsored offer. + :param data: The sponsored data. + :param claimable_balance_id: The sponsored claimable balance. + :param signer: The sponsored signer. + :param source: The source account (defaults to transaction source). """ def __init__( @@ -276,9 +300,9 @@ def _to_operation_body(self) -> Xdr.nullclass: ledger_key.type = Xdr.const.CLAIMABLE_BALANCE claimable_balance_bytes = binascii.unhexlify(self.claimable_balance_id) claimable_balance = Xdr.nullclass() - balance_id = Xdr.nullclass() - balance_id.type = Xdr.const.CLAIMABLE_BALANCE_ID_TYPE_V0 # int32 - balance_id.v0 = claimable_balance_bytes[4:] + balance_id = ClaimableBalanceID.from_xdr( + base64.b64encode(claimable_balance_bytes) + ) claimable_balance.balanceID = balance_id ledger_key.claimableBalance = claimable_balance revoke_sponsorship_op = Xdr.nullclass() @@ -338,7 +362,9 @@ def from_xdr_object( data_name = ledger_key.data.dataName.decode() op = cls.revoke_data_sponsorship(account_id, data_name, source) elif ledger_key_type == Xdr.const.CLAIMABLE_BALANCE: - balance_id = b"\x00" * 4 + ledger_key.claimableBalance.balanceID.v0 + balance_id = base64.b64decode( + ledger_key.claimableBalance.balanceID.to_xdr() + ) balance_id = binascii.hexlify(balance_id).decode() op = cls.revoke_claimable_balance_sponsorship(balance_id, source) else: