diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 000000000..bd6db6799 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,4 @@ +# TODO: Delete this .coveragerc file once the ledger objects models are incorporated into the rest of the code. +[run] +omit = + */xrpl/models/ledger_objects/* diff --git a/docs/source/xrpl.models.ledger_objects.rst b/docs/source/xrpl.models.ledger_objects.rst new file mode 100644 index 000000000..6de6d3c21 --- /dev/null +++ b/docs/source/xrpl.models.ledger_objects.rst @@ -0,0 +1,22 @@ +XRPL Ledger Objects Models +=================================== + +Use these models to process XRP Ledger Objects. + +Base Ledger Object Model +---------------------- + +.. autoclass:: xrpl.models.ledger_objects.ledger_object.LedgerObject + :members: + :undoc-members: + :show-inheritance: + :inherited-members: + +Specific Ledger Object Types +-------------------------- + +.. automodule:: xrpl.models.ledger_objects + :members: + :undoc-members: + :show-inheritance: + :inherited-members: diff --git a/tests/unit/models/ledger_objects/__init__.py b/tests/unit/models/ledger_objects/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/unit/models/ledger_objects/test_account_root.py b/tests/unit/models/ledger_objects/test_account_root.py new file mode 100644 index 000000000..6cab8b736 --- /dev/null +++ b/tests/unit/models/ledger_objects/test_account_root.py @@ -0,0 +1,47 @@ +from unittest import TestCase + +from xrpl.models.ledger_objects.account_root import AccountRoot +from xrpl.models.ledger_objects.ledger_object import LedgerObject + + +class TestAccountRoot(TestCase): + def test_account_root(self): + account_root_json = { + "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "AccountTxnID": "0D5FB50FA65C9FE1538FD7E398FFFE9D190" + "8DFA4576D8D7A020040686F93C77D", + "Balance": "148446663", + "Domain": "6D64756F31332E636F6D", + "EmailHash": "98B4375E1D753E5B91627516F6D70977", + "Flags": 8388608, + "LedgerEntryType": "AccountRoot", + "MessageKey": "0000000000000000000000070000000300", + "OwnerCount": 3, + "NFTokenMinter": "rHello", + "PreviousTxnID": "0D5FB50FA65C9FE1538FD7E398FFFE9D1908DFA4576D8D7A0200" + "40686F93C77D", + "PreviousTxnLgrSeq": 14091160, + "Sequence": 336, + "TransferRate": 1004999999, + "index": "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8", + } + actual = LedgerObject.from_xrpl(account_root_json) + expected = AccountRoot( + index="13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8", + account="rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + balance="148446663", + flags=8388608, + owner_count=3, + previous_txn_id="0D5FB50FA65C9FE1538FD7E398FFFE9D" + "1908DFA4576D8D7A020040686F93C77D", + previous_txn_lgr_seq=14091160, + sequence=336, + account_txn_id="0D5FB50FA65C9FE1538FD7E398FFFE9D1" + "908DFA4576D8D7A020040686F93C77D", + domain="6D64756F31332E636F6D", + email_hash="98B4375E1D753E5B91627516F6D70977", + message_key="0000000000000000000000070000000300", + nftoken_minter="rHello", + transfer_rate=1004999999, + ) + self.assertEqual(actual, expected) diff --git a/tests/unit/models/ledger_objects/test_amendments.py b/tests/unit/models/ledger_objects/test_amendments.py new file mode 100644 index 000000000..84c14da72 --- /dev/null +++ b/tests/unit/models/ledger_objects/test_amendments.py @@ -0,0 +1,47 @@ +from unittest import TestCase + +from xrpl.models.ledger_objects.amendments import Amendments, Majority +from xrpl.models.ledger_objects.ledger_object import LedgerObject + + +class TestAmendments(TestCase): + def test_amendments(self): + amendment_json = { + "Majorities": [ + { + "Majority": { + "Amendment": "1562511F573A19AE9BD103B5D6B9E01B3B46805AEC" + "5D3C4805C902B51" + "4399146", + "CloseTime": 535589001, + } + } + ], + "Amendments": [ + "42426C4D4F1009EE67080A9B7965B44656D7714D104A72F9B4369F97ABF044EE", + "4C97EBA926031A7CF7D7B36FDE3ED66DDA5421192D63DE53FFB46E43B9DC8373", + "6781F8368C4771B83E8B821D88F580202BCB4228075297B19E4FDC5233F1EFDC", + "740352F2412A9909880C23A559FCECEDA3BE2126FED62FC7660D628A06927F11", + ], + "Flags": 0, + "LedgerEntryType": "Amendments", + "index": "7DB0788C020F02780A673DC74757F23823FA3014C1866E72CC4CD8B226CD6EF4", + } + actual = LedgerObject.from_xrpl(amendment_json) + expected = Amendments( + index="7DB0788C020F02780A673DC74757F23823FA3014C1866E72CC4CD8B226CD6EF4", + amendments=[ + "42426C4D4F1009EE67080A9B7965B44656D7714D104A72F9B4369F97ABF044EE", + "4C97EBA926031A7CF7D7B36FDE3ED66DDA5421192D63DE53FFB46E43B9DC8373", + "6781F8368C4771B83E8B821D88F580202BCB4228075297B19E4FDC5233F1EFDC", + "740352F2412A9909880C23A559FCECEDA3BE2126FED62FC7660D628A06927F11", + ], + majorities=[ + Majority( + amendment="1562511F573A19AE9BD103B5D6B9E01B3B46805AEC5D3C" + "4805C902B514399146", + close_time=535589001, + ) + ], + ) + self.assertEqual(actual, expected) diff --git a/tests/unit/models/ledger_objects/test_amm.py b/tests/unit/models/ledger_objects/test_amm.py new file mode 100644 index 000000000..d5158c94b --- /dev/null +++ b/tests/unit/models/ledger_objects/test_amm.py @@ -0,0 +1,90 @@ +from unittest import TestCase + +from xrpl.models.amounts.issued_currency_amount import IssuedCurrencyAmount +from xrpl.models.auth_account import AuthAccount +from xrpl.models.currencies.issued_currency import IssuedCurrency +from xrpl.models.currencies.xrp import XRP +from xrpl.models.ledger_objects.amm import AMM, AuctionSlot, VoteEntry +from xrpl.models.ledger_objects.ledger_object import LedgerObject + + +class TestAMM(TestCase): + def test_amm(self): + amm_json = { + "Account": "rE54zDvgnghAoPopCgvtiqWNq3dU5y836S", + "Asset": {"currency": "XRP"}, + "Asset2": { + "currency": "TST", + "issuer": "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd", + }, + "AuctionSlot": { + "Account": "rJVUeRqDFNs2xqA7ncVE6ZoAhPUoaJJSQm", + "AuthAccounts": [ + {"AuthAccount": {"Account": "rMKXGCbJ5d8LbrqthdG46q3f969MVK2Qeg"}}, + {"AuthAccount": {"Account": "rBepJuTLFJt3WmtLXYAxSjtBWAeQxVbncv"}}, + ], + "DiscountedFee": 0, + "Expiration": 721870180, + "Price": { + "currency": "039C99CD9AB0B70B32ECDA51EAAE471625608EA2", + "issuer": "rE54zDvgnghAoPopCgvtiqWNq3dU5y836S", + "value": "0.8696263565463045", + }, + }, + "LPTokenBalance": { + "currency": "039C99CD9AB0B70B32ECDA51EAAE471625608EA2", + "issuer": "rE54zDvgnghAoPopCgvtiqWNq3dU5y836S", + "value": "71150.53584131501", + }, + "TradingFee": 600, + "VoteSlots": [ + { + "VoteEntry": { + "Account": "rJVUeRqDFNs2xqA7ncVE6ZoAhPUoaJJSQm", + "TradingFee": 600, + "VoteWeight": 100000, + } + } + ], + "OwnerNode": "0", + "Flags": 0, + "LedgerEntryType": "AMM", + } + actual = LedgerObject.from_xrpl(amm_json) + expected = AMM( + account="rE54zDvgnghAoPopCgvtiqWNq3dU5y836S", + asset=XRP(), + asset2=IssuedCurrency( + currency="TST", + issuer="rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd", + ), + auction_slot=AuctionSlot( + account="rJVUeRqDFNs2xqA7ncVE6ZoAhPUoaJJSQm", + auth_accounts=[ + AuthAccount(account="rMKXGCbJ5d8LbrqthdG46q3f969MVK2Qeg"), + AuthAccount(account="rBepJuTLFJt3WmtLXYAxSjtBWAeQxVbncv"), + ], + discounted_fee=0, + expiration=721870180, + price=IssuedCurrencyAmount( + currency="039C99CD9AB0B70B32ECDA51EAAE471625608EA2", + issuer="rE54zDvgnghAoPopCgvtiqWNq3dU5y836S", + value="0.8696263565463045", + ), + ), + owner_node="0", + lp_token_balance=IssuedCurrencyAmount( + currency="039C99CD9AB0B70B32ECDA51EAAE471625608EA2", + issuer="rE54zDvgnghAoPopCgvtiqWNq3dU5y836S", + value="71150.53584131501", + ), + trading_fee=600, + vote_slots=[ + VoteEntry( + account="rJVUeRqDFNs2xqA7ncVE6ZoAhPUoaJJSQm", + trading_fee=600, + vote_weight=100000, + ), + ], + ) + self.assertEqual(actual, expected) diff --git a/tests/unit/models/ledger_objects/test_bridge.py b/tests/unit/models/ledger_objects/test_bridge.py new file mode 100644 index 000000000..cdd7f61cc --- /dev/null +++ b/tests/unit/models/ledger_objects/test_bridge.py @@ -0,0 +1,53 @@ +from unittest import TestCase + +from xrpl.models.currencies.xrp import XRP +from xrpl.models.ledger_objects.bridge import Bridge +from xrpl.models.ledger_objects.ledger_object import LedgerObject +from xrpl.models.xchain_bridge import XChainBridge + + +class TestBridge(TestCase): + def test_bridge(self): + bridge_json = { + "Account": "r3nCVTbZGGYoWvZ58BcxDmiMUU7ChMa1eC", + "Flags": 0, + "LedgerEntryType": "Bridge", + "MinAccountCreateAmount": "2000000000", + "OwnerNode": "0", + "PreviousTxnID": "67A8A1B36C1B97BE3AAB6B19CB3A3069034877DE" + "917FD1A71919EAE7548E56" + "36", + "PreviousTxnLgrSeq": 102, + "SignatureReward": "204", + "XChainAccountClaimCount": "0", + "XChainAccountCreateCount": "0", + "XChainBridge": { + "IssuingChainDoor": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", + "IssuingChainIssue": {"currency": "XRP"}, + "LockingChainDoor": "r3nCVTbZGGYoWvZ58BcxDmiMUU7ChMa1eC", + "LockingChainIssue": {"currency": "XRP"}, + }, + "XChainClaimID": "1", + "index": "9F2C9E23343852036AFD323025A8506018ABF9D4DBAA746D61BF1CFB5C297D10", + } + actual = LedgerObject.from_xrpl(bridge_json) + expected = Bridge( + account="r3nCVTbZGGYoWvZ58BcxDmiMUU7ChMa1eC", + min_account_create_amount="2000000000", + owner_node="0", + previous_txn_id="67A8A1B36C1B97BE3AAB6B19CB3A3069034877DE917FD1A71919EAE75" + "48E5636", + previous_txn_lgr_seq=102, + signature_reward="204", + xchain_account_claim_count="0", + xchain_account_create_count="0", + xchain_bridge=XChainBridge( + issuing_chain_door="rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", + issuing_chain_issue=XRP(), + locking_chain_door="r3nCVTbZGGYoWvZ58BcxDmiMUU7ChMa1eC", + locking_chain_issue=XRP(), + ), + xchain_claim_id="1", + index="9F2C9E23343852036AFD323025A8506018ABF9D4DBAA746D61BF1CFB5C297D10", + ) + self.assertEqual(actual, expected) diff --git a/tests/unit/models/ledger_objects/test_check.py b/tests/unit/models/ledger_objects/test_check.py new file mode 100644 index 000000000..5a38fd0d8 --- /dev/null +++ b/tests/unit/models/ledger_objects/test_check.py @@ -0,0 +1,44 @@ +from unittest import TestCase + +from xrpl.models.ledger_objects.check import Check +from xrpl.models.ledger_objects.ledger_object import LedgerObject + + +class TestCheck(TestCase): + def test_check(self): + check_json = { + "Account": "rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo", + "Destination": "rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy", + "DestinationNode": "0000000000000000", + "DestinationTag": 1, + "Expiration": 570113521, + "Flags": 0, + "InvoiceID": "46060241FABCF692D4D934BA2A6C4427CD4279083E3" + "8C77CBE642243E43BE291", + "LedgerEntryType": "Check", + "OwnerNode": "0000000000000000", + "PreviousTxnID": "5463C6E08862A1FAE5EDAC12D70ADB16546A1F67" + "4930521295BC082494B62924", + "PreviousTxnLgrSeq": 6, + "SendMax": "100000000", + "Sequence": 2, + "index": "49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0", + } + actual = LedgerObject.from_xrpl(check_json) + expected = Check( + index="49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0", + account="rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo", + destination="rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy", + owner_node="0000000000000000", + previous_txn_id="5463C6E08862A1FAE5EDAC12D70ADB16546A" + "1F674930521295BC082494B62924", + previous_txn_lgr_seq=6, + send_max="100000000", + sequence=2, + destination_node="0000000000000000", + destination_tag=1, + expiration=570113521, + invoice_id="46060241FABCF692D4D934BA2A6C4427CD427" + "9083E38C77CBE642243E43BE291", + ) + self.assertEqual(actual, expected) diff --git a/tests/unit/models/ledger_objects/test_deposit_preauth.py b/tests/unit/models/ledger_objects/test_deposit_preauth.py new file mode 100644 index 000000000..57bf8dbdc --- /dev/null +++ b/tests/unit/models/ledger_objects/test_deposit_preauth.py @@ -0,0 +1,30 @@ +from unittest import TestCase + +from xrpl.models.ledger_objects.deposit_preauth import DepositPreauth +from xrpl.models.ledger_objects.ledger_object import LedgerObject + + +class TestDepositPreauth(TestCase): + def test_deposit_preauth(self): + deposit_preauth_json = { + "LedgerEntryType": "DepositPreauth", + "Account": "rsUiUMpnrgxQp24dJYZDhmV4bE3aBtQyt8", + "Authorize": "rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de", + "Flags": 0, + "OwnerNode": "0000000000000000", + "PreviousTxnID": "3E8964D5A86B3CD6B9ECB33310D4E073D64C865A5B866200" + "AD2B7E29F8326702", + "PreviousTxnLgrSeq": 7, + "index": "4A255038CC3ADCC1A9C91509279B59908251728D0DAADB248FFE297D0F7E068C", + } + actual = LedgerObject.from_xrpl(deposit_preauth_json) + expected = DepositPreauth( + index="4A255038CC3ADCC1A9C91509279B59908251728D0DAADB248FFE297D0F7E068C", + account="rsUiUMpnrgxQp24dJYZDhmV4bE3aBtQyt8", + authorize="rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de", + owner_node="0000000000000000", + previous_txn_id="3E8964D5A86B3CD6B9ECB33310D4E073D64C8" + "65A5B866200AD2B7E29F8326702", + previous_txn_lgr_seq=7, + ) + self.assertEqual(actual, expected) diff --git a/tests/unit/models/ledger_objects/test_did.py b/tests/unit/models/ledger_objects/test_did.py new file mode 100644 index 000000000..6396f463a --- /dev/null +++ b/tests/unit/models/ledger_objects/test_did.py @@ -0,0 +1,34 @@ +from unittest import TestCase + +from xrpl.models.ledger_objects.did import DID +from xrpl.models.ledger_objects.ledger_object import LedgerObject + + +class TestDID(TestCase): + def test_did(self): + did_json = { + "Account": "rpfqJrXg5uidNo2ZsRhRY6TiF1cvYmV9Fg", + "DIDDocument": "646F63", + "Data": "617474657374", + "Flags": 0, + "LedgerEntryType": "DID", + "OwnerNode": "0", + "PreviousTxnID": "A4C15DA185E6092DF5954FF62A1446220C61A5F60F0D93B4B0" + "9F708778E41120", + "PreviousTxnLgrSeq": 4, + "URI": "6469645F6578616D706C65", + "index": "46813BE38B798B3752CA590D44E7FEADB17485649074403AD1761A2835CE91FF", + } + actual = LedgerObject.from_xrpl(did_json) + expected = DID( + account="rpfqJrXg5uidNo2ZsRhRY6TiF1cvYmV9Fg", + did_document="646F63", + data="617474657374", + owner_node="0", + previous_txn_id="A4C15DA185E6092DF5954FF62A1446220C61A5F60F0D93B4B09F" + "708778E41120", + previous_txn_lgr_seq=4, + uri="6469645F6578616D706C65", + index="46813BE38B798B3752CA590D44E7FEADB17485649074403AD1761A2835CE91FF", + ) + self.assertEqual(actual, expected) diff --git a/tests/unit/models/ledger_objects/test_directory_node.py b/tests/unit/models/ledger_objects/test_directory_node.py new file mode 100644 index 000000000..f4c9b579d --- /dev/null +++ b/tests/unit/models/ledger_objects/test_directory_node.py @@ -0,0 +1,38 @@ +from unittest import TestCase + +from xrpl.models.ledger_objects.directory_node import DirectoryNode +from xrpl.models.ledger_objects.ledger_object import LedgerObject + + +class TestDirectoryNode(TestCase): + def test_directory_node(self): + directory_node_json = { + "ExchangeRate": "4F069BA8FF484000", + "Flags": 0, + "Indexes": [ + "AD7EAE148287EF12D213A251015F86E6D4BD34B3C4A0A1ED9A17198373F908AD" + ], + "LedgerEntryType": "DirectoryNode", + "RootIndex": "1BBEF97EDE88D40CEE2ADE6FEF121166AFE80D99EBADB01A" + "4F069BA8FF484000", + "TakerGetsCurrency": "0000000000000000000000000000000000000000", + "TakerGetsIssuer": "0000000000000000000000000000000000000000", + "TakerPaysCurrency": "0000000000000000000000004A50590000000000", + "TakerPaysIssuer": "5BBC0F22F61D9224A110650CFE21CC0C4BE13098", + "index": "1BBEF97EDE88D40CEE2ADE6FEF121166AFE80D99EBADB01A4F069BA8FF484000", + } + actual = LedgerObject.from_xrpl(directory_node_json) + expected = DirectoryNode( + index="1BBEF97EDE88D40CEE2ADE6FEF121166AFE80D99EBADB01A4F069BA8FF484000", + root_index="1BBEF97EDE88D40CEE2ADE6FEF121166A" + "FE80D99EBADB01A4F069BA8FF484000", + indexes=[ + "AD7EAE148287EF12D213A251015F86E6D4BD34B3C4A0A1ED9A17198373F908AD" + ], + exchange_rate="4F069BA8FF484000", + taker_pays_currency="0000000000000000000000004A50590000000000", + taker_pays_issuer="5BBC0F22F61D9224A110650CFE21CC0C4BE13098", + taker_gets_currency="0000000000000000000000000000000000000000", + taker_gets_issuer="0000000000000000000000000000000000000000", + ) + self.assertEqual(actual, expected) diff --git a/tests/unit/models/ledger_objects/test_escrow.py b/tests/unit/models/ledger_objects/test_escrow.py new file mode 100644 index 000000000..fc2360606 --- /dev/null +++ b/tests/unit/models/ledger_objects/test_escrow.py @@ -0,0 +1,47 @@ +from unittest import TestCase + +from xrpl.models.ledger_objects.escrow import Escrow +from xrpl.models.ledger_objects.ledger_object import LedgerObject + + +class TestEscrow(TestCase): + def test_escrow(self): + escrow_json = { + "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Amount": "10000", + "CancelAfter": 545440232, + "Condition": "A0258020A82A88B2DF843A54F58772E4A386" + "1866ECDB4157645DD9AE528C1D3AEEDAB" + "AB6810120", + "Destination": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX", + "DestinationTag": 23480, + "FinishAfter": 545354132, + "Flags": 0, + "LedgerEntryType": "Escrow", + "OwnerNode": "0000000000000000", + "DestinationNode": "0000000000000000", + "PreviousTxnID": "C44F2EB84196B9AD820313DBEBA6316A15C9A2" + "D35787579ED172B87A30131DA7", + "PreviousTxnLgrSeq": 28991004, + "SourceTag": 11747, + "index": "DC5F3851D8A1AB622F957761E5963BC5BD439D5C24AC6AD7AC4523F0640244AC", + } + actual = LedgerObject.from_xrpl(escrow_json) + expected = Escrow( + index="DC5F3851D8A1AB622F957761E5963BC5BD439D5C24AC6AD7AC4523F0640244AC", + account="rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + amount="10000", + destination="ra5nK24KXen9AHvsdFTKHSANinZseWnPcX", + owner_node="0000000000000000", + previous_txn_id="C44F2EB84196B9AD820313DBEBA6316A15" + "C9A2D35787579ED172B87A30131DA7", + previous_txn_lgr_seq=28991004, + condition="A0258020A82A88B2DF843A54F58772E4A3861866EC" + "DB4157645DD9AE528C1D3AEEDABAB6810120", + cancel_after=545440232, + destination_node="0000000000000000", + destination_tag=23480, + finish_after=545354132, + source_tag=11747, + ) + self.assertEqual(actual, expected) diff --git a/tests/unit/models/ledger_objects/test_fee_settings.py b/tests/unit/models/ledger_objects/test_fee_settings.py new file mode 100644 index 000000000..90a8f6c21 --- /dev/null +++ b/tests/unit/models/ledger_objects/test_fee_settings.py @@ -0,0 +1,26 @@ +from unittest import TestCase + +from xrpl.models.ledger_objects.fee_settings import FeeSettings +from xrpl.models.ledger_objects.ledger_object import LedgerObject + + +class TestFeeSettings(TestCase): + def test_fee_settings(self): + fee_settings_json = { + "BaseFee": "000000000000000A", + "Flags": 0, + "LedgerEntryType": "FeeSettings", + "ReferenceFeeUnits": 10, + "ReserveBase": 20000000, + "ReserveIncrement": 5000000, + "index": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A651", + } + actual = LedgerObject.from_xrpl(fee_settings_json) + expected = FeeSettings( + index="4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A651", + base_fee="000000000000000A", + reference_fee_units=10, + reserve_base=20000000, + reserve_increment=5000000, + ) + self.assertEqual(actual, expected) diff --git a/tests/unit/models/ledger_objects/test_ledger_hashes.py b/tests/unit/models/ledger_objects/test_ledger_hashes.py new file mode 100644 index 000000000..fb3e2fc1d --- /dev/null +++ b/tests/unit/models/ledger_objects/test_ledger_hashes.py @@ -0,0 +1,36 @@ +from unittest import TestCase + +from xrpl.models.ledger_objects.ledger_hashes import LedgerHashes +from xrpl.models.ledger_objects.ledger_object import LedgerObject + + +class TestLedgerHashes(TestCase): + def test_ledger_hashes(self): + ledger_hashes_json = { + "LedgerEntryType": "LedgerHashes", + "Flags": 0, + "FirstLedgerSequence": 2, + "LastLedgerSequence": 33872029, + "Hashes": [ + "D638208ADBD04CBB10DE7B645D3AB4BA31489379411A3A347151702B6401AA78", + "254D690864E418DDD9BCAC93F41B1F53B1AE693FC5FE667CE40205C322D1BE3B", + "A2B31D28905E2DEF926362822BC412B12ABF6942B73B72A32D46ED2ABB7ACCFA", + "AB4014846DF818A4B43D6B1686D0DE0644FE711577C5AB6F0B2A21CCEE280140", + "3383784E82A8BA45F4DD5EF4EE90A1B2D3B4571317DBAC37B859836ADDE644C1", + ], + "index": "B4979A36CDC7F3D3D5C31A4EAE2AC7D7209DDA877588B9AFC66799692AB0D66B", + } + actual = LedgerObject.from_xrpl(ledger_hashes_json) + expected = LedgerHashes( + index="B4979A36CDC7F3D3D5C31A4EAE2AC7D7209DDA877588B9AFC66799692AB0D66B", + first_ledger_sequence=2, + last_ledger_sequence=33872029, + hashes=[ + "D638208ADBD04CBB10DE7B645D3AB4BA31489379411A3A347151702B6401AA78", + "254D690864E418DDD9BCAC93F41B1F53B1AE693FC5FE667CE40205C322D1BE3B", + "A2B31D28905E2DEF926362822BC412B12ABF6942B73B72A32D46ED2ABB7ACCFA", + "AB4014846DF818A4B43D6B1686D0DE0644FE711577C5AB6F0B2A21CCEE280140", + "3383784E82A8BA45F4DD5EF4EE90A1B2D3B4571317DBAC37B859836ADDE644C1", + ], + ) + self.assertEqual(actual, expected) diff --git a/tests/unit/models/ledger_objects/test_negative_unl.py b/tests/unit/models/ledger_objects/test_negative_unl.py new file mode 100644 index 000000000..e2e36bc72 --- /dev/null +++ b/tests/unit/models/ledger_objects/test_negative_unl.py @@ -0,0 +1,34 @@ +from unittest import TestCase + +from xrpl.models.ledger_objects.ledger_object import LedgerObject +from xrpl.models.ledger_objects.negative_unl import DisabledValidator, NegativeUNL + + +class TestNegativeUNL(TestCase): + def test_negative_unl(self): + negative_unl_json = { + "DisabledValidators": [ + { + "DisabledValidator": { + "FirstLedgerSequence": 1609728, + "PublicKey": "ED6629D456285AE3613B285F65BBFF168D695BA" + "3921F309949AFCD2CA7AFEC16FE", + } + } + ], + "Flags": 0, + "LedgerEntryType": "NegativeUNL", + "index": "2E8A59AA9D3B5B186B0B9E0F62E6C02587CA74A4D778938E957B6357D364B244", + } + actual = LedgerObject.from_xrpl(negative_unl_json) + expected = NegativeUNL( + index="2E8A59AA9D3B5B186B0B9E0F62E6C02587CA74A4D778938E957B6357D364B244", + disabled_validators=[ + DisabledValidator( + first_ledger_sequence=1609728, + public_key="ED6629D456285AE3613B285F65BBFF168D695BA" + "3921F309949AFCD2CA7AFEC16FE", + ) + ], + ) + self.assertEqual(actual, expected) diff --git a/tests/unit/models/ledger_objects/test_nftoken_offer.py b/tests/unit/models/ledger_objects/test_nftoken_offer.py new file mode 100644 index 000000000..4cac83ab8 --- /dev/null +++ b/tests/unit/models/ledger_objects/test_nftoken_offer.py @@ -0,0 +1,38 @@ +from unittest import TestCase + +from xrpl.models.ledger_objects.ledger_object import LedgerObject +from xrpl.models.ledger_objects.nftoken_offer import NFTokenOffer + + +class TestNFTokenOffer(TestCase): + def test_nftoken_offer(self): + nftoken_offer_json = { + "LedgerEntryType": "NFTokenOffer", + "index": "AEBABA4FAC212BF28E0F9A9C3788A47B085557EC5D1429E7A8266FB859C863B3", + "Amount": "1000000", + "Flags": 1, + "NFTokenID": "00081B5825A08C22787716FA031B432EBBC1B101BB54875F0002D2A40000" + "0000", + "Owner": "rhRxL3MNvuKEjWjL7TBbZSDacb8PmzAd7m", + "PreviousTxnID": "BFA9BE27383FA315651E26FDE1FA30815C5A5D0544EE10EC33D3E925" + "32993" + "769", + "PreviousTxnLgrSeq": 75443565, + "OwnerNode": "17", + "NFTokenOfferNode": "0", + } + actual = LedgerObject.from_xrpl(nftoken_offer_json) + expected = NFTokenOffer( + index="AEBABA4FAC212BF28E0F9A9C3788A47B085557EC5D1429E7A8266FB859C863B3", + amount="1000000", + flags=1, + nftoken_id="00081B5825A08C22787716FA031B432EBBC1B101BB54875F0002D2A400000" + "000", + owner="rhRxL3MNvuKEjWjL7TBbZSDacb8PmzAd7m", + previous_txn_id="BFA9BE27383FA315651E26FDE1FA30815C5A5D0544EE10EC33D3E925" + "32993769", + previous_txn_lgr_seq=75443565, + owner_node="17", + nftoken_offer_node="0", + ) + self.assertEqual(actual, expected) diff --git a/tests/unit/models/ledger_objects/test_nftoken_page.py b/tests/unit/models/ledger_objects/test_nftoken_page.py new file mode 100644 index 000000000..cd709d566 --- /dev/null +++ b/tests/unit/models/ledger_objects/test_nftoken_page.py @@ -0,0 +1,44 @@ +from unittest import TestCase + +from xrpl.models.ledger_objects.ledger_object import LedgerObject +from xrpl.models.ledger_objects.nftoken_offer import NFToken +from xrpl.models.ledger_objects.nftoken_page import NFTokenPage + + +class TestNFTokenPage(TestCase): + def test_nftoken_page(self): + nftoken_page_json = { + "Flags": 0, + "LedgerEntryType": "NFTokenPage", + "PreviousTxnID": "95C8761B22894E328646F7A70035E9DFBECC9" + "0EDD83E43B7B973F626D21A0822", + "PreviousTxnLgrSeq": 42891441, + "NFTokens": [ + { + "nftoken_id": "000B013A95F14B0044F78A264E41713" + "C64B5F89242540EE208C3098E00000D65", + "uri": "697066733A2F2F62616679626569676479727A74357366703775646D376" + "8753736" + "7568377932366E6634646675796C71616266336F636C67747179353566627A64" + "69", + }, + ], + "index": "", + } + actual = LedgerObject.from_xrpl(nftoken_page_json) + expected = NFTokenPage( + index="", + previous_txn_id="95C8761B22894E328646F7A70035E9DFBEC" + "C90EDD83E43B7B973F626D21A0822", + previous_txn_lgr_seq=42891441, + nftokens=[ + NFToken( + nftoken_id="000B013A95F14B0044F78A264E41713" + "C64B5F89242540EE208C3098E00000D65", + uri="697066733A2F2F62616679626569676479727A" + "74357366703775646D37687537367568377932366E" + "6634646675796C71616266336F636C67747179353566627A6469", + ) + ], + ) + self.assertEqual(actual, expected) diff --git a/tests/unit/models/ledger_objects/test_offer.py b/tests/unit/models/ledger_objects/test_offer.py new file mode 100644 index 000000000..e8b992980 --- /dev/null +++ b/tests/unit/models/ledger_objects/test_offer.py @@ -0,0 +1,48 @@ +from unittest import TestCase + +from xrpl.models.amounts.issued_currency_amount import IssuedCurrencyAmount +from xrpl.models.ledger_objects.ledger_object import LedgerObject +from xrpl.models.ledger_objects.offer import Offer + + +class TestOffer(TestCase): + def test_offer(self): + offer_json = { + "Account": "rBqb89MRQJnMPq8wTwEbtz4kvxrEDfcYvt", + "BookDirectory": "ACC27DE91DBA86FC509069EAF4BC511D7" + "3128B780F2E54BF5E07A369E2446000", + "BookNode": "0000000000000000", + "Flags": 131072, + "LedgerEntryType": "Offer", + "OwnerNode": "0000000000000000", + "PreviousTxnID": "F0AB71E777B2DA54B86231E19B82554EF1" + "F8211F92ECA473121C655BFC5329BF", + "PreviousTxnLgrSeq": 14524914, + "Sequence": 866, + "TakerGets": { + "currency": "XAG", + "issuer": "r9Dr5xwkeLegBeXq6ujinjSBLQzQ1zQGjH", + "value": "37", + }, + "TakerPays": "79550000000", + "index": "96F76F27D8A327FC48753167EC04A46AA0E382E6F57F32FD12274144D00F1797", + } + actual = LedgerObject.from_xrpl(offer_json) + expected = Offer( + index="96F76F27D8A327FC48753167EC04A46AA0E382E6F57F32FD12274144D00F1797", + account="rBqb89MRQJnMPq8wTwEbtz4kvxrEDfcYvt", + taker_gets=IssuedCurrencyAmount( + currency="XAG", issuer="r9Dr5xwkeLegBeXq6ujinjSBLQzQ1zQGjH", value="37" + ), + taker_pays="79550000000", + sequence=866, + flags=131072, + book_directory="ACC27DE91DBA86FC509069EAF4BC511D7" + "3128B780F2E54BF5E07A369E2446000", + book_node="0000000000000000", + owner_node="0000000000000000", + previous_txn_id="F0AB71E777B2DA54B86231E19B82554EF1F821" + "1F92ECA473121C655BFC5329BF", + previous_txn_lgr_seq=14524914, + ) + self.assertEqual(actual, expected) diff --git a/tests/unit/models/ledger_objects/test_pay_channel.py b/tests/unit/models/ledger_objects/test_pay_channel.py new file mode 100644 index 000000000..c7b4ee8cc --- /dev/null +++ b/tests/unit/models/ledger_objects/test_pay_channel.py @@ -0,0 +1,51 @@ +from unittest import TestCase + +from xrpl.models.ledger_objects.ledger_object import LedgerObject +from xrpl.models.ledger_objects.pay_channel import PayChannel + + +class TestPayChannel(TestCase): + def test_pay_channel(self): + pay_channel_json = { + "Account": "rBqb89MRQJnMPq8wTwEbtz4kvxrEDfcYvt", + "Destination": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Amount": "4325800", + "Balance": "2323423", + "PublicKey": "32D2471DB72B27E3310F355BB33E339BF26F8392D5A93D3BC0FC3B566612D" + "A0F0A", + "SettleDelay": 3600, + "Expiration": 536027313, + "CancelAfter": 536891313, + "SourceTag": 0, + "DestinationTag": 1002341, + "DestinationNode": "0000000000000000", + "Flags": 0, + "LedgerEntryType": "PayChannel", + "OwnerNode": "0000000000000000", + "PreviousTxnID": "F0AB71E777B2DA54B86231E19B82554E" + "F1F8211F92ECA473121C655BFC5329BF", + "PreviousTxnLgrSeq": 14524914, + "index": "96F76F27D8A327FC48753167EC04A46AA0E382E6F57F32FD12274144D00F1797", + } + actual = LedgerObject.from_xrpl(pay_channel_json) + expected = PayChannel( + index="96F76F27D8A327FC48753167EC04A46AA0E382E6F57F32FD12274144D00F1797", + account="rBqb89MRQJnMPq8wTwEbtz4kvxrEDfcYvt", + amount="4325800", + balance="2323423", + destination="rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + flags=0, + owner_node="0000000000000000", + public_key="32D2471DB72B27E3310F355BB33E339BF26F83" + "92D5A93D3BC0FC3B566612DA0F0A", + previous_txn_id="F0AB71E777B2DA54B86231E19B82554EF1" + "F8211F92ECA473121C655BFC5329BF", + previous_txn_lgr_seq=14524914, + settle_delay=3600, + destination_node="0000000000000000", + destination_tag=1002341, + expiration=536027313, + cancel_after=536891313, + source_tag=0, + ) + self.assertEqual(actual, expected) diff --git a/tests/unit/models/ledger_objects/test_ripple_state.py b/tests/unit/models/ledger_objects/test_ripple_state.py new file mode 100644 index 000000000..bd17c8682 --- /dev/null +++ b/tests/unit/models/ledger_objects/test_ripple_state.py @@ -0,0 +1,54 @@ +from unittest import TestCase + +from xrpl.models.amounts.issued_currency_amount import IssuedCurrencyAmount +from xrpl.models.ledger_objects.ledger_object import LedgerObject +from xrpl.models.ledger_objects.ripple_state import RippleState + + +class TestRippleState(TestCase): + def test_ripple_state(self): + ripple_state_json = { + "Balance": { + "currency": "USD", + "issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji", + "value": "-10", + }, + "Flags": 393216, + "HighLimit": { + "currency": "USD", + "issuer": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "value": "110", + }, + "HighNode": "0000000000000000", + "LedgerEntryType": "RippleState", + "LowLimit": { + "currency": "USD", + "issuer": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW", + "value": "0", + }, + "LowNode": "0000000000000000", + "PreviousTxnID": "E3FE6EA3D48F0C2B639448020EA4F03D" + "4F4F8FFDB243A852A0F59177921B4879", + "PreviousTxnLgrSeq": 14090896, + "index": "9CA88CDEDFF9252B3DE183CE35B038F57282BC9503CDFA1923EF9A95DF0D6F7B", + } + actual = LedgerObject.from_xrpl(ripple_state_json) + expected = RippleState( + index="9CA88CDEDFF9252B3DE183CE35B038F57282BC9503CDFA1923EF9A95DF0D6F7B", + balance=IssuedCurrencyAmount( + currency="USD", issuer="rrrrrrrrrrrrrrrrrrrrBZbvji", value="-10" + ), + flags=393216, + low_limit=IssuedCurrencyAmount( + currency="USD", issuer="rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW", value="0" + ), + high_limit=IssuedCurrencyAmount( + currency="USD", issuer="rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", value="110" + ), + previous_txn_id="E3FE6EA3D48F0C2B639448020EA4F03D4F4" + "F8FFDB243A852A0F59177921B4879", + previous_txn_lgr_seq=14090896, + high_node="0000000000000000", + low_node="0000000000000000", + ) + self.assertEqual(actual, expected) diff --git a/tests/unit/models/ledger_objects/test_signer_list.py b/tests/unit/models/ledger_objects/test_signer_list.py new file mode 100644 index 000000000..3b5153d97 --- /dev/null +++ b/tests/unit/models/ledger_objects/test_signer_list.py @@ -0,0 +1,66 @@ +from unittest import TestCase + +from xrpl.models.ledger_objects.ledger_object import LedgerObject +from xrpl.models.ledger_objects.signer_list import SignerList +from xrpl.models.transactions.signer_list_set import SignerEntry + + +class TestSignerList(TestCase): + def test_signer_list(self): + signer_list_json = { + "Flags": 0, + "LedgerEntryType": "SignerList", + "OwnerNode": "0000000000000000", + "PreviousTxnID": "5904C0DC72C58A83AEFED2FFC5386356" + "AA83FCA6A88C89D00646E51E687CDBE4", + "PreviousTxnLgrSeq": 16061435, + "SignerEntries": [ + { + "SignerEntry": { + "Account": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW", + "SignerWeight": 2, + } + }, + { + "SignerEntry": { + "Account": "raKEEVSGnKSD9Zyvxu4z6Pqpm4ABH8FS6n", + "SignerWeight": 1, + } + }, + { + "SignerEntry": { + "Account": "rUpy3eEg8rqjqfUoLeBnZkscbKbFsKXC3v", + "SignerWeight": 1, + } + }, + ], + "SignerListID": 0, + "SignerQuorum": 3, + "index": "A9C28A28B85CD533217F5C0A0C7767666B093FA58A0F2D80026FCC4CD932DDC7", + } + actual = LedgerObject.from_xrpl(signer_list_json) + expected = SignerList( + index="A9C28A28B85CD533217F5C0A0C7767666B093FA58A0F2D80026FCC4CD932DDC7", + flags=0, + owner_node="0000000000000000", + previous_txn_id="5904C0DC72C58A83AEFED2FFC5386356" + "AA83FCA6A88C89D00646E51E687CDBE4", + previous_txn_lgr_seq=16061435, + signer_entries=[ + SignerEntry( + account="rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW", + signer_weight=2, + ), + SignerEntry( + account="raKEEVSGnKSD9Zyvxu4z6Pqpm4ABH8FS6n", + signer_weight=1, + ), + SignerEntry( + account="rUpy3eEg8rqjqfUoLeBnZkscbKbFsKXC3v", + signer_weight=1, + ), + ], + signer_list_id=0, + signer_quorum=3, + ) + self.assertEqual(actual, expected) diff --git a/tests/unit/models/ledger_objects/test_ticket.py b/tests/unit/models/ledger_objects/test_ticket.py new file mode 100644 index 000000000..07ee31c63 --- /dev/null +++ b/tests/unit/models/ledger_objects/test_ticket.py @@ -0,0 +1,31 @@ +from unittest import TestCase + +from xrpl.models.ledger_objects.ledger_object import LedgerObject +from xrpl.models.ledger_objects.ticket import Ticket + + +class TestTicket(TestCase): + def test_ticket(self): + ticket_json = { + "Account": "rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de", + "Flags": 0, + "LedgerEntryType": "Ticket", + "OwnerNode": "0000000000000000", + "PreviousTxnID": "F19AD4577212D3BEACA0F75FE1BA1" + "644F2E854D46E8D62E9C95D18E9708CBFB1", + "PreviousTxnLgrSeq": 4, + "TicketSequence": 3, + "index": "A9C28A28B85CD533217F5C0A0C7767666B093FA58A0F2D80026FCC4CD932DDC7", + } + actual = LedgerObject.from_xrpl(ticket_json) + expected = Ticket( + index="A9C28A28B85CD533217F5C0A0C7767666B093FA58A0F2D80026FCC4CD932DDC7", + account="rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de", + flags=0, + owner_node="0000000000000000", + previous_txn_id="F19AD4577212D3BEACA0F75FE1BA1644F2E85" + "4D46E8D62E9C95D18E9708CBFB1", + previous_txn_lgr_seq=4, + ticket_sequence=3, + ) + self.assertEqual(actual, expected) diff --git a/tests/unit/models/ledger_objects/test_xchain_owned_claim_id.py b/tests/unit/models/ledger_objects/test_xchain_owned_claim_id.py new file mode 100644 index 000000000..d4bceca2b --- /dev/null +++ b/tests/unit/models/ledger_objects/test_xchain_owned_claim_id.py @@ -0,0 +1,104 @@ +from unittest import TestCase + +from xrpl.models.currencies.xrp import XRP +from xrpl.models.ledger_objects.ledger_object import LedgerObject +from xrpl.models.ledger_objects.xchain_owned_claim_id import ( + XChainClaimProofSig, + XChainOwnedClaimID, +) +from xrpl.models.xchain_bridge import XChainBridge + + +class TestXChainOwnedClaimID(TestCase): + def test_xchain_owned_claim_id(self): + xchain_owned_claim_id_json = { + "Account": "rBW1U7J9mEhEdk6dMHEFUjqQ7HW7WpaEMi", + "Flags": 0, + "OtherChainSource": "r9oXrvBX5aDoyMGkoYvzazxDhYoWFUjz8p", + "OwnerNode": "0", + "PreviousTxnID": "1CFD80E9CF232B8EED62A52857DE97438D12230C0" + "6496932A81DEFA6E660" + "70A6", + "PreviousTxnLgrSeq": 58673, + "SignatureReward": "100", + "XChainBridge": { + "IssuingChainDoor": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", + "IssuingChainIssue": {"currency": "XRP"}, + "LockingChainDoor": "rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4", + "LockingChainIssue": {"currency": "XRP"}, + }, + "XChainClaimAttestations": [ + { + "XChainClaimProofSig": { + "Amount": "1000000", + "AttestationRewardAccount": "rfgjrgEJGDxfUY2U8VEDs7BnB1jiH3of" + "u6", + "AttestationSignerAccount": "rfsxNxZ6xB1nTPhTMwQajNnkCxWG8B71" + "4n", + "Destination": "rBW1U7J9mEhEdk6dMHEFUjqQ7HW7WpaEMi", + "PublicKey": "025CA526EF20567A50FEC504589F949E0E3401C13EF76DD" + "5FD1CC285" + "0FA485BD7B", + "WasLockingChainSend": 1, + } + }, + { + "XChainClaimProofSig": { + "Amount": "1000000", + "AttestationRewardAccount": "rUUL1tP523M8KimERqVS7sxb1tLLmpnd" + "yv", + "AttestationSignerAccount": "rEg5sHxZVTNwRL3BAdMwJatkmWDzHMmz" + "DF", + "Destination": "rBW1U7J9mEhEdk6dMHEFUjqQ7HW7WpaEMi", + "PublicKey": "03D40434A6843638681E2F215310EBC4131AFB12EA85985" + "DA073183B" + "732525F7C9", + "WasLockingChainSend": 1, + }, + }, + ], + "XChainClaimID": "b5", + "LedgerEntryType": "XChainOwnedClaimID", + "LedgerIndex": "20B136D7BF6D2E3D610E28E3E6BE09F5C8F4F0241BBF6E2D072AE1BAC" + "B1388F5", + } + actual = LedgerObject.from_xrpl(xchain_owned_claim_id_json) + expected = XChainOwnedClaimID( + account="rBW1U7J9mEhEdk6dMHEFUjqQ7HW7WpaEMi", + other_chain_source="r9oXrvBX5aDoyMGkoYvzazxDhYoWFUjz8p", + owner_node="0", + previous_txn_id="1CFD80E9CF232B8EED62A52857DE97438D12230C06496932A81DEFA6E6" + "6070A6", + previous_txn_lgr_seq=58673, + signature_reward="100", + xchain_bridge=XChainBridge( + issuing_chain_door="rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", + issuing_chain_issue=XRP(), + locking_chain_door="rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4", + locking_chain_issue=XRP(), + ), + xchain_claim_attestations=[ + XChainClaimProofSig( + amount="1000000", + attestation_reward_account="rfgjrgEJGDxfUY2U8VEDs7BnB1jiH3ofu6", + attestation_signer_account="rfsxNxZ6xB1nTPhTMwQajNnkCxWG8B714n", + destination="rBW1U7J9mEhEdk6dMHEFUjqQ7HW7WpaEMi", + public_key="025CA526EF20567A50FEC504589F949E0E3401C13EF76DD5FD1CC2" + "850FA485BD7B", + was_locking_chain_send=1, + ), + XChainClaimProofSig( + amount="1000000", + attestation_reward_account="rUUL1tP523M8KimERqVS7sxb1tLLmpndyv", + attestation_signer_account="rEg5sHxZVTNwRL3BAdMwJatkmWDzHMmzDF", + destination="rBW1U7J9mEhEdk6dMHEFUjqQ7HW7WpaEMi", + public_key="03D40434A6843638681E2F215310EBC4131AFB12EA85985DA07318" + "3B732525F7C9", + was_locking_chain_send=1, + ), + ], + xchain_claim_id="b5", + ledger_index="20B136D7BF6D2E3D610E28E3E6BE09F5C8F4F0241BBF6E2D072AE1BACB13" + "88F5", + ) + self.assertEqual(actual, expected) diff --git a/tests/unit/models/ledger_objects/test_xchain_owned_create_account_claim_id.py b/tests/unit/models/ledger_objects/test_xchain_owned_create_account_claim_id.py new file mode 100644 index 000000000..5aea225d4 --- /dev/null +++ b/tests/unit/models/ledger_objects/test_xchain_owned_create_account_claim_id.py @@ -0,0 +1,78 @@ +from unittest import TestCase + +from xrpl.models.currencies.xrp import XRP +from xrpl.models.ledger_objects.ledger_object import LedgerObject +from xrpl.models.ledger_objects.xchain_owned_create_account_claim_id import ( + XChainCreateAccountProofSig, + XChainOwnedCreateAccountClaimID, +) +from xrpl.models.xchain_bridge import XChainBridge + + +class TestXChainOwnedCreateAccountClaimID(TestCase): + def test_xchain_owned_create_account_claim_id(self): + xchain_owned_create_account_claim_id_json = { + "Flags": 0, + "LedgerEntryType": "XChainOwnedCreateAccountClaimID", + "LedgerIndex": "5A92F6ED33FDA68FB4B9FD140EA38C056CD2BA9673ECA5B4CEF40F2166B" + "B6F0C", + "OwnerNode": "0", + "PreviousTxnID": "1CFD80E9CF232B8EED62A52857DE97438D12230C06496932A81DEFA6" + "E660", + "PreviousTxnLgrSeq": 58673, + "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", + "XChainAccountCreateCount": "66", + "XChainBridge": { + "IssuingChainDoor": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", + "IssuingChainIssue": {"currency": "XRP"}, + "LockingChainDoor": "rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4", + "LockingChainIssue": {"currency": "XRP"}, + }, + "XChainCreateAccountAttestations": [ + { + "XChainCreateAccountProofSig": { + "Amount": "20000000", + "AttestationRewardAccount": "rMtYb1vNdeMDpD9tA5qSFm8WXEBdEo" + "KKVw", + "AttestationSignerAccount": "rL8qTrAvZ8Q1o1H9H9Ahpj3xjgmRvF" + "LvJ3", + "Destination": "rBW1U7J9mEhEdk6dMHEFUjqQ7HW7WpaEMi", + "PublicKey": "021F7CC4033EFBE5E8214B04D1BAAEC14808DC6C02F4A" + "CE930A8" + "EF0F5909B0C438", + "SignatureReward": "100", + "WasLockingChainSend": 1, + } + } + ], + } + actual = LedgerObject.from_xrpl(xchain_owned_create_account_claim_id_json) + expected = XChainOwnedCreateAccountClaimID( + account="rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", + owner_node="0", + previous_txn_id="1CFD80E9CF232B8EED62A52857DE97438D12230C06496932A81D" + "EFA6E660", + previous_txn_lgr_seq=58673, + ledger_index="5A92F6ED33FDA68FB4B9FD140EA38C056CD2BA9673ECA5B4CEF40F2166B" + "B6F0C", + xchain_account_create_count="66", + xchain_bridge=XChainBridge( + issuing_chain_door="rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", + issuing_chain_issue=XRP(), + locking_chain_door="rMAXACCrp3Y8PpswXcg3bKggHX76V3F8M4", + locking_chain_issue=XRP(), + ), + xchain_create_account_attestations=[ + XChainCreateAccountProofSig( + amount="20000000", + attestation_reward_account="rMtYb1vNdeMDpD9tA5qSFm8WXEBdEoKKVw", + attestation_signer_account="rL8qTrAvZ8Q1o1H9H9Ahpj3xjgmRvFLvJ3", + destination="rBW1U7J9mEhEdk6dMHEFUjqQ7HW7WpaEMi", + public_key="021F7CC4033EFBE5E8214B04D1BAAEC14808DC6C02F4ACE930A8E" + "F0F5909B0C438", + signature_reward="100", + was_locking_chain_send=1, + ) + ], + ) + self.assertEqual(actual, expected) diff --git a/xrpl/models/flags.py b/xrpl/models/flags.py index 67662b8f0..345faf800 100644 --- a/xrpl/models/flags.py +++ b/xrpl/models/flags.py @@ -35,6 +35,7 @@ def interface_to_flag_list( A list of flags expressed as integers. """ from xrpl.models import transactions # Avoid circular dependencies + from xrpl.models import ledger_objects # Get all exported classes with names of the form `{TxType}Flag` # These are all the flag value enums for transactions/pseudo-transactions @@ -44,6 +45,7 @@ def interface_to_flag_list( pseudo_tx_flag_enums = [ f for f in transactions.pseudo_transactions.__all__ if f.endswith("Flag") ] + ledger_object_flag_enums = [f for f in ledger_objects.__all__ if f.endswith("Flag")] # Key is transaction type name, value is mapping of flag name to int value all_tx_flags: Dict[str, Dict[str, int]] = { @@ -54,6 +56,10 @@ def interface_to_flag_list( f[:-4]: _flag_enum_to_dict(getattr(transactions.pseudo_transactions, f)) for f in pseudo_tx_flag_enums }, + **{ + f[:-4]: _flag_enum_to_dict(getattr(ledger_objects, f)) + for f in ledger_object_flag_enums + }, } # if transaction types has no flags diff --git a/xrpl/models/ledger_objects/__init__.py b/xrpl/models/ledger_objects/__init__.py new file mode 100644 index 000000000..214f9d0d9 --- /dev/null +++ b/xrpl/models/ledger_objects/__init__.py @@ -0,0 +1,69 @@ +"""The models for Ledger Objects""" + +from xrpl.models.ledger_objects.account_root import AccountRoot, AccountRootFlags +from xrpl.models.ledger_objects.amendments import Amendments, Majority +from xrpl.models.ledger_objects.amm import AMM +from xrpl.models.ledger_objects.bridge import Bridge +from xrpl.models.ledger_objects.check import Check +from xrpl.models.ledger_objects.deposit_preauth import DepositPreauth +from xrpl.models.ledger_objects.did import DID +from xrpl.models.ledger_objects.directory_node import DirectoryNode +from xrpl.models.ledger_objects.escrow import Escrow +from xrpl.models.ledger_objects.fee_settings import FeeSettings +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_hashes import LedgerHashes +from xrpl.models.ledger_objects.ledger_object import LedgerObject +from xrpl.models.ledger_objects.negative_unl import DisabledValidator, NegativeUNL +from xrpl.models.ledger_objects.nftoken_offer import ( + NFToken, + NFTokenOffer, + NFTokenOfferFlags, +) +from xrpl.models.ledger_objects.nftoken_page import NFTokenPage +from xrpl.models.ledger_objects.offer import Offer, OfferFlag +from xrpl.models.ledger_objects.pay_channel import PayChannel +from xrpl.models.ledger_objects.ripple_state import RippleState +from xrpl.models.ledger_objects.signer_list import ( + SignerEntry, + SignerList, + SignerListFlag, +) +from xrpl.models.ledger_objects.ticket import Ticket +from xrpl.models.ledger_objects.xchain_owned_claim_id import XChainOwnedClaimID +from xrpl.models.ledger_objects.xchain_owned_create_account_claim_id import ( + XChainOwnedCreateAccountClaimID, +) + +__all__ = [ + "AccountRoot", + "AccountRootFlags", + "Amendments", + "AMM", + "Bridge", + "Check", + "DepositPreauth", + "DID", + "DirectoryNode", + "DisabledValidator", + "Escrow", + "FeeSettings", + "LedgerEntryType", + "LedgerHashes", + "LedgerObject", + "Majority", + "NegativeUNL", + "NFToken", + "NFTokenOffer", + "NFTokenOfferFlags", + "NFTokenPage", + "Offer", + "OfferFlag", + "PayChannel", + "RippleState", + "SignerEntry", + "SignerList", + "SignerListFlag", + "Ticket", + "XChainOwnedClaimID", + "XChainOwnedCreateAccountClaimID", +] diff --git a/xrpl/models/ledger_objects/account_root.py b/xrpl/models/ledger_objects/account_root.py new file mode 100644 index 000000000..56fb8ab82 --- /dev/null +++ b/xrpl/models/ledger_objects/account_root.py @@ -0,0 +1,153 @@ +"""Models for the Ledger Object `AccountRoot`""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from enum import Enum +from typing import Optional + +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_object import HasPreviousTxnID, LedgerObject +from xrpl.models.required import REQUIRED +from xrpl.models.utils import require_kwargs_on_init + + +@require_kwargs_on_init +@dataclass(frozen=True) +class AccountRoot(LedgerObject, HasPreviousTxnID): + """The model for the `AccountRoot` Ledger Object""" + + account: str = REQUIRED # type: ignore + """ + The identifying (classic) address of this account. This field is required. + """ + + account_txn_id: Optional[str] = None + """ + The identifying hash of the transaction most recently sent by this account. This + field must be enabled to use the `AccountTxnID` transaction field. To enable it, + send an AccountSet transaction with the `asfAccountTxnID` flag enabled. + """ + + amm_id: Optional[str] = None + """ + The ledger entry ID of the corresponding AMM ledger entry. Set during account + creation; cannot be modified. If present, indicates that this is a special AMM + AccountRoot; always omitted on non-AMM accounts. + """ + + balance: str = REQUIRED # type: ignore + """ + The account's current XRP balance in drops, represented as a string. This field is + required. + """ + + burned_nftokens: Optional[int] = None + """ + How many total of this account's issued non-fungible tokens have been burned. This + number is always equal or less than `MintedNFTokens`. + """ + + domain: Optional[str] = None + """ + A domain associated with this account. In JSON, this is the hexadecimal for the + ASCII representation of the domain. Cannot be more than 256 bytes in length. + """ + + email_hash: Optional[str] = None + """ + The md5 hash of an email address. Clients can use this to look up an avatar through + services such as Gravatar. + """ + + first_nftoken_sequence: Optional[int] = None + """ + The account's Sequence Number at the time it minted its first non-fungible token. + """ + + message_key: Optional[str] = None + """ + A public key that may be used to send encrypted messages to this account. In JSON, + uses hexadecimal. Must be exactly 33 bytes, with the first byte indicating the key + type: `0x02` or `0x03` for secp256k1 keys, `0xED` for Ed25519 keys. + """ + + minted_nftokens: Optional[int] = None + """ + How many total non-fungible tokens have been minted by and on behalf of this + account. + """ + + nftoken_minter: Optional[str] = None + """ + Another account that can mint non-fungible tokens on behalf of this account. + """ + + owner_count: int = REQUIRED # type: ignore + """ + The number of objects this account owns in the ledger, which contributes to its + owner reserve. + """ + + regular_key: Optional[str] = None + """ + The address of a key pair that can be used to sign transactions for this account + instead of the master key. Use a `SetRegularKey` transaction to change this value. + """ + + sequence: int = REQUIRED # type: ignore + """ + The sequence number of the next valid transaction for this account. + """ + + ticket_count: Optional[int] = None + """ + How many Tickets this account owns in the ledger. This is updated automatically to + ensure that the account stays within the hard limit of 250 Tickets at a time. This + field is omitted if the account has zero Tickets. + """ + + tick_size: Optional[int] = None + """ + How many significant digits to use for exchange rates of Offers involving + currencies issued by this address. Valid values are 3 to 15, inclusive. + """ + + transfer_rate: Optional[int] = None + """ + A transfer fee to charge other users for sending currency issued by this account to + each other. + """ + + wallet_locator: Optional[str] = None + """ + An arbitrary 256-bit value that users can set. + """ + + wallet_size: Optional[int] = None + """ + Unused. (The code supports this field but there is no way to set it.) + """ + + ledger_entry_type: LedgerEntryType = field( + default=LedgerEntryType.ACCOUNT_ROOT, init=False + ) + + +class AccountRootFlags(Enum): + """The flags for the `AccountRoot` Ledger Object""" + + LSF_ALLOW_TRUSTLINE_CLAWBACK = 0x80000000 + LSF_DEFAULT_RIPPLE = 0x00800000 + LSF_DEPOSIT_AUTH = 0x01000000 + LSF_DISABLE_MASTER = 0x00100000 + LSF_DISALLOW_INCOMING_CHECK = 0x08000000 + LSF_DISALLOW_INCOMING_NFTOKEN_OFFER = 0x04000000 + LSF_DISALLOW_INCOMING_PAY_CHAN = 0x10000000 + LSF_DISALLOW_INCOMING_TRUSTLINE = 0x20000000 + LSF_DISALLOW_XRP = 0x00080000 + LSF_GLOBAL_FREEZE = 0x00400000 + LSF_NO_FREEZE = 0x00200000 + LSF_PASSWORD_SPENT = 0x00010000 + LSF_REQUIRE_AUTH = 0x00040000 + LSF_REQUIRE_DEST_TAG = 0x00020000 diff --git a/xrpl/models/ledger_objects/amendments.py b/xrpl/models/ledger_objects/amendments.py new file mode 100644 index 000000000..265ee66e1 --- /dev/null +++ b/xrpl/models/ledger_objects/amendments.py @@ -0,0 +1,45 @@ +"""Models for the Ledger Object `Amendments`""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import List, Optional + +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_object import LedgerObject +from xrpl.models.nested_model import NestedModel +from xrpl.models.required import REQUIRED +from xrpl.models.utils import require_kwargs_on_init + + +@require_kwargs_on_init +@dataclass(frozen=True) +class Amendments(LedgerObject): + """The model for the `Amendments` Ledger Object""" + + amendments: Optional[List[str]] = None + """ + Array of 256-bit amendment IDs for all currently enabled amendments. If omitted, + there are no enabled amendments. + """ + + ledger_entry_type: LedgerEntryType = field( + default=LedgerEntryType.AMENDMENTS, + init=False, + ) + + majorities: Optional[List[Majority]] = None + """ + Array of objects describing the status of amendments that have majority support but + are not yet enabled. If omitted, there are no pending amendments with majority + support. + """ + + +@require_kwargs_on_init +@dataclass(frozen=True) +class Majority(NestedModel): + """A model for the `Majority` object""" + + amendment: str = REQUIRED # type: ignore + close_time: int = REQUIRED # type: ignore diff --git a/xrpl/models/ledger_objects/amm.py b/xrpl/models/ledger_objects/amm.py new file mode 100644 index 000000000..bd4bf0844 --- /dev/null +++ b/xrpl/models/ledger_objects/amm.py @@ -0,0 +1,138 @@ +"""Models for the Ledger Object `AMM`""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import List, Optional + +from xrpl.models.amounts.issued_currency_amount import IssuedCurrencyAmount +from xrpl.models.auth_account import AuthAccount +from xrpl.models.base_model import BaseModel +from xrpl.models.currencies import Currency +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_object import LedgerObject +from xrpl.models.nested_model import NestedModel +from xrpl.models.required import REQUIRED +from xrpl.models.utils import require_kwargs_on_init + + +@require_kwargs_on_init +@dataclass(frozen=True) +class AMM(LedgerObject): + """The model for the `AMM` Ledger Object""" + + account: str = REQUIRED # type: ignore + """ + The address of the special account that holds this AMM's assets. + This field is required. + """ + + asset: Currency = REQUIRED # type: ignore + """ + The definition for one of the two assets this AMM holds. This field is required. + """ + + asset2: Currency = REQUIRED # type: ignore + """ + The definition for the other asset this AMM holds. This field is required. + """ + + auction_slot: Optional[AuctionSlot] = None + """ + Details of the current owner of the auction slot, as an Auction Slot object. + """ + + lp_token_balance: IssuedCurrencyAmount = REQUIRED # type: ignore + """ + The total outstanding balance of liquidity provider tokens from this AMM instance. + The holders of these tokens can vote on the AMM's trading fee in proportion to + their holdings, or redeem the tokens for a share of the AMM's assets which grows + with the trading fees collected. This field is required. + """ + + trading_fee: int = REQUIRED # type: ignore + """ + The percentage fee to be charged for trades against this AMM instance, in units + of 1/100,000. The maximum value is 1000, for a 1% fee. This field is required. + """ + + vote_slots: Optional[List[VoteEntry]] = None + """ + A list of vote objects, representing votes on the pool's trading fee. + """ + + owner_node: str = REQUIRED # type: ignore + """ + A hint indicating which page of the sender's owner directory links to this entry, + in case the directory consists of multiple pages. + """ + + ledger_entry_type: LedgerEntryType = field( + default=LedgerEntryType.AMM, + init=False, + ) + + +@require_kwargs_on_init +@dataclass(frozen=True) +class AuctionSlot(BaseModel): + """ + The model for the `AuctionSlot` object + Details of the current owner of the auction slot. + """ + + account: str = REQUIRED # type: ignore + """ + The current owner of this auction slot. This field is required. + """ + + auth_accounts: Optional[List[AuthAccount]] = None + """ + A list of at most 4 additional accounts that are authorized to trade at the + discounted fee for this AMM instance. + """ + + discounted_fee: int = REQUIRED # type: ignore + """ + The trading fee to be charged to the auction owner, in the same format as + TradingFee. + By default this is 0, meaning that the auction owner can trade at no fee instead of + the standard fee for this AMM. This field is required. + """ + + expiration: int = REQUIRED # type: ignore + """ + The time when this slot expires, in seconds since the Ripple Epoch. + This field is required. + """ + + price: IssuedCurrencyAmount = REQUIRED # type: ignore + """ + The amount the auction owner paid to win this slot, in LP Tokens. + This field is required. + """ + + +@require_kwargs_on_init +@dataclass(frozen=True) +class VoteEntry(NestedModel): + """A model for the `VoteEntry` object""" + + account: str = REQUIRED # type: ignore + """ + The account that cast the vote. This field is required. + """ + + trading_fee: int = REQUIRED # type: ignore + """ + The proposed trading fee, in units of 1/100,000; a value of 1 is equivalent + to 0.001%. The maximum value is 1000, indicating a 1% fee. This field is required. + """ + + vote_weight: int = REQUIRED # type: ignore + """ + The weight of the vote, in units of 1/100,000. For example, a value of 1234 means + this vote counts as 1.234% of the weighted total vote. The weight is determined by + the percentage of this AMM's LP Tokens the account owns. The maximum value is + 100000. This field is required. + """ diff --git a/xrpl/models/ledger_objects/bridge.py b/xrpl/models/ledger_objects/bridge.py new file mode 100644 index 000000000..fe42e9954 --- /dev/null +++ b/xrpl/models/ledger_objects/bridge.py @@ -0,0 +1,80 @@ +"""Models for the Ledger Object `Bridge`""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Optional, Union + +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_object import HasPreviousTxnID, LedgerObject +from xrpl.models.required import REQUIRED +from xrpl.models.utils import require_kwargs_on_init +from xrpl.models.xchain_bridge import XChainBridge + + +@require_kwargs_on_init +@dataclass(frozen=True) +class Bridge(LedgerObject, HasPreviousTxnID): + """The model for the `Bridge` Ledger Object""" + + account: str = REQUIRED # type: ignore + """ + The account that submitted the `XChainCreateBridge` transaction on the blockchain. + This field is required. + """ + + min_account_create_amount: Optional[str] = None + """ + The minimum amount, in XRP, required for an `XChainAccountCreateCommit` transaction. + If this isn't present, the `XChainAccountCreateCommit` transaction will fail. + This field can only be present on XRP-XRP bridges. + """ + + signature_reward: str = REQUIRED # type: ignore + """ + The total amount, in XRP, to be rewarded for providing a signature for cross-chain + transfer or for signing for the cross-chain reward. This amount will be split among + the signers. This field is required. + """ + + xchain_account_claim_count: Union[int, str] = REQUIRED # type: ignore + """ + A counter used to order the execution of account create transactions. It is + incremented every time a `XChainAccountCreateCommit` transaction is "claimed" on the + destination chain. When the "claim" transaction is run on the destination chain, + the XChainAccountClaimCount must match the value that the XChainAccountCreateCount + had at the time the XChainAccountClaimCount was run on the source chain. This + orders the claims so that they run in the same order that the + `XChainAccountCreateCommit` transactions ran on the source chain, to prevent + transaction replay. This field is required. + """ + + xchain_account_create_count: Union[int, str] = REQUIRED # type: ignore + """ + A counter used to order the execution of account create transactions. It is + incremented every time a successful `XChainAccountCreateCommit` transaction is run + for the source chain. This field is required. + """ + + xchain_bridge: XChainBridge = REQUIRED # type: ignore + """ + A counter used to order the execution of account create transactions. It is + incremented every time a successful `XChainAccountCreateCommit` transaction is run + for the source chain. This field is required. + """ + + xchain_claim_id: Union[int, str] = REQUIRED # type: ignore + """ + The value of the next `XChainClaimID` to be created. This field is required. + """ + + owner_node: str = REQUIRED # type: ignore + """ + A hint indicating which page of the sender's owner directory links to this entry, + in case the directory consists of multiple pages. + """ + + ledger_entry_type: LedgerEntryType = field( + default=LedgerEntryType.BRIDGE, + init=False, + ) diff --git a/xrpl/models/ledger_objects/check.py b/xrpl/models/ledger_objects/check.py new file mode 100644 index 000000000..ec0162406 --- /dev/null +++ b/xrpl/models/ledger_objects/check.py @@ -0,0 +1,84 @@ +"""Models for the Ledger Object `Check`""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Optional, Union + +from xrpl.models.amounts.issued_currency_amount import IssuedCurrencyAmount +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_object import HasPreviousTxnID, LedgerObject +from xrpl.models.required import REQUIRED +from xrpl.models.utils import require_kwargs_on_init + + +@require_kwargs_on_init +@dataclass(frozen=True) +class Check(LedgerObject, HasPreviousTxnID): + """The model for the `Check` Ledger Object""" + + account: str = REQUIRED # type: ignore + """ + The sender of the Check. Cashing the Check debits this address's balance. + This field is required. + """ + + destination: str = REQUIRED # type: ignore + """ + The intended recipient of the Check. Only this address can cash the Check, using a + `CheckCash` transaction. This field is required. + """ + + destination_node: str = REQUIRED # type: ignore + """ + A hint indicating which page of the destination's owner directory links to this + object, in case the directory consists of multiple pages. + """ + + destination_tag: Optional[int] = None + """ + An arbitrary tag to further specify the destination for this Check, such as a + hosted recipient at the destination address. + """ + + expiration: Optional[int] = None + """ + Indicates the time after which this Check is considered expired. See Specifying + Time for details. + """ + + invoice_id: Optional[str] = None + """ + Arbitrary 256-bit hash provided by the sender as a specific reason or identifier + for this Check. + """ + + owner_node: str = REQUIRED # type: ignore + """ + A hint indicating which page of the sender's owner directory links to this object, + in case the directory consists of multiple pages. This field is required. + """ + + send_max: Union[str, IssuedCurrencyAmount] = REQUIRED # type: ignore + """ + The maximum amount of currency this Check can debit the sender. If the Check is + successfully cashed, the destination is credited in the same currency for up to + this amount. This field is required. + """ + + sequence: int = REQUIRED # type: ignore + """ + The sequence number of the `CheckCreate` transaction that created this check. + This field is required. + """ + + source_tag: Optional[int] = None + """ + An arbitrary tag to further specify the source for this Check, such as a hosted + recipient at the sender's address. + """ + + ledger_entry_type: LedgerEntryType = field( + default=LedgerEntryType.CHECK, + init=False, + ) diff --git a/xrpl/models/ledger_objects/deposit_preauth.py b/xrpl/models/ledger_objects/deposit_preauth.py new file mode 100644 index 000000000..a3dda1326 --- /dev/null +++ b/xrpl/models/ledger_objects/deposit_preauth.py @@ -0,0 +1,41 @@ +"""Models for the Ledger Object `DepositPreauth`""" + +from __future__ import annotations + +from dataclasses import dataclass, field + +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_object import HasPreviousTxnID, LedgerObject +from xrpl.models.required import REQUIRED +from xrpl.models.utils import require_kwargs_on_init + + +@require_kwargs_on_init +@dataclass(frozen=True) +class DepositPreauth(LedgerObject, HasPreviousTxnID): + """The model for the `DepositPreauth` Ledger Object""" + + account: str = REQUIRED # type: ignore + """ + The account that granted the preauthorization. (The destination of the + preauthorized payments.) This field is required. + """ + + authorize: str = REQUIRED # type: ignore + """ + The account that received the preauthorization. (The sender of the preauthorized + payments.) This field is required. + """ + + owner_node: str = REQUIRED # type: ignore + """ + A hint indicating which page of the sender's owner directory links to this object, + in case the directory consists of multiple pages. Note: The object does not contain + a direct link to the owner directory containing it, since that value can be derived + from the Account. This field is required. + """ + + ledger_entry_type: LedgerEntryType = field( + default=LedgerEntryType.DEPOSIT_PREAUTH, + init=False, + ) diff --git a/xrpl/models/ledger_objects/did.py b/xrpl/models/ledger_objects/did.py new file mode 100644 index 000000000..a86146ef7 --- /dev/null +++ b/xrpl/models/ledger_objects/did.py @@ -0,0 +1,53 @@ +"""Models for the Ledger Object `DID`""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Optional + +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_object import HasPreviousTxnID, LedgerObject +from xrpl.models.required import REQUIRED +from xrpl.models.utils import require_kwargs_on_init + + +@require_kwargs_on_init +@dataclass(frozen=True) +class DID(LedgerObject, HasPreviousTxnID): + """The model for the `DID` Ledger Object""" + + account: str = REQUIRED # type: ignore + """ + The account that controls the DID. This field is required. + """ + + did_document: Optional[str] = None + """ + The W3C standard DID document associated with the DID. The `DIDDocument` field isn't + checked for validity and is limited to a maximum length of 256 bytes. + """ + + data: Optional[str] = None + """ + The public attestations of identity credentials associated with the DID. The `Data` + field isn't checked for validity and is limited to a maximum length of 256 bytes. + """ + + owner_node: str = REQUIRED # type: ignore + """ + A hint indicating which page of the sender's owner directory links to this entry, + in case the directory consists of multiple pages. + """ + + uri: Optional[str] = None + """ + The Universal Resource Identifier that points to the corresponding DID document or + the data associated with the DID. This field can be an HTTP(S) URL or IPFS URI. + This field isn't checked for validity and is limited to a maximum length of 256 + bytes. + """ + + ledger_entry_type: LedgerEntryType = field( + default=LedgerEntryType.DID, + init=False, + ) diff --git a/xrpl/models/ledger_objects/directory_node.py b/xrpl/models/ledger_objects/directory_node.py new file mode 100644 index 000000000..bf5eeb905 --- /dev/null +++ b/xrpl/models/ledger_objects/directory_node.py @@ -0,0 +1,85 @@ +"""Models for the Ledger Object `DirectoryNode`""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import List, Optional + +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_object import LedgerObject +from xrpl.models.required import REQUIRED +from xrpl.models.utils import require_kwargs_on_init + + +@require_kwargs_on_init +@dataclass(frozen=True) +class DirectoryNode(LedgerObject): + """The model for the `DirectoryNode` Ledger Object""" + + exchange_rate: Optional[str] = None + """ + (Offer Directories only) DEPRECATED. Do not use. + """ + + indexes: List[str] = REQUIRED # type: ignore + """ + The contents of this Directory: an array of IDs of other objects. + This field is required. + """ + + index_next: Optional[str] = None + """ + If this Directory consists of multiple pages, this ID links to the next object in + the chain, wrapping around at the end. + """ + + index_previous: Optional[str] = None + """ + If this Directory consists of multiple pages, this ID links to the previous object + in the chain, wrapping around at the beginning. This field is required. + """ + + owner: Optional[str] = None + """ + (Owner Directories only) The address of the account that owns the objects in this + directory. + """ + + root_index: str = REQUIRED # type: ignore + """ + The ID of root object for this directory. This field is required. + """ + + taker_gets_currency: Optional[str] = None + """ + (Offer Directories only) The currency code of the `TakerGets` amount from the offers + in this directory. + """ + + taker_gets_issuer: Optional[str] = None + """ + (Offer Directories only) The issuer of the `TakerGets` amount from the offers in + this directory. + """ + + taker_pays_currency: Optional[str] = None + """ + (Offer Directories only) The currency code of the `TakerPays` amount from the offers + in this directory. + """ + + taker_pays_issuer: Optional[str] = None + """ + (Offer Directories only) The issuer of the `TakerPays` amount from the offers in + this directory. + """ + + nftoken_id: Optional[str] = None + """ + (Non-Fungible Token Directories only) The ID of the non-fungible token. + """ + + ledger_entry_type: LedgerEntryType = field( + default=LedgerEntryType.DIRECTORY_NODE, + init=False, + ) diff --git a/xrpl/models/ledger_objects/escrow.py b/xrpl/models/ledger_objects/escrow.py new file mode 100644 index 000000000..1a8af81bd --- /dev/null +++ b/xrpl/models/ledger_objects/escrow.py @@ -0,0 +1,84 @@ +"""Models for the Ledger Object `Escrow`""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Optional + +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_object import HasPreviousTxnID, LedgerObject +from xrpl.models.required import REQUIRED +from xrpl.models.utils import require_kwargs_on_init + + +@require_kwargs_on_init +@dataclass(frozen=True) +class Escrow(LedgerObject, HasPreviousTxnID): + """The model for the `Escrow` Ledger Object""" + + account: str = REQUIRED # type: ignore + """ + The address of the owner (sender) of this escrow. This is the account that provided + the XRP, and gets it back if the escrow is canceled. This field is required. + """ + + amount: str = REQUIRED # type: ignore + """ + The amount of XRP, in drops, currently held in the escrow. This field is required. + """ + + destination: str = REQUIRED # type: ignore + """ + The destination address where the XRP is paid if the escrow is successful. + This field is required. + """ + + owner_node: str = REQUIRED # type: ignore + """ + A hint indicating which page of the sender's owner directory links to this entry, + in case the directory consists of multiple pages. This field is required. + """ + + condition: Optional[str] = None + """ + A PREIMAGE-SHA-256 crypto-condition , as hexadecimal. If present, the `EscrowFinish` + transaction must contain a fulfillment that satisfies this condition. + """ + + cancel_after: Optional[int] = None + """ + The escrow can be canceled if and only if this field is present and the time it + specifies has passed. Specifically, this is specified as seconds since the Ripple + Epoch and it "has passed" if it's earlier than the close time of the previous + validated ledger. + """ + + destination_node: Optional[str] = None + """ + A hint indicating which page of the destination's owner directory links to this + object, in case the directory consists of multiple pages. Omitted on escrows + created before enabling the fix1523 amendment. + """ + + destination_tag: Optional[int] = None + """ + An arbitrary tag to further specify the destination for this escrow, such as a + hosted recipient at the destination address. + """ + + finish_after: Optional[int] = None + """ + The time, in seconds since the Ripple Epoch, after which this escrow can be + finished. Any `EscrowFinish` transaction before this time fails. (Specifically, this + is compared with the close time of the previous validated ledger.) + """ + + source_tag: Optional[int] = None + """ + An arbitrary tag to further specify the source for this escrow, such as a hosted + recipient at the owner's address. + """ + + ledger_entry_type: LedgerEntryType = field( + default=LedgerEntryType.ESCROW, init=False + ) diff --git a/xrpl/models/ledger_objects/fee_settings.py b/xrpl/models/ledger_objects/fee_settings.py new file mode 100644 index 000000000..3fa8476d1 --- /dev/null +++ b/xrpl/models/ledger_objects/fee_settings.py @@ -0,0 +1,58 @@ +"""Models for the Ledger Object `FeeSettings`""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Optional + +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_object import LedgerObject +from xrpl.models.utils import require_kwargs_on_init + + +@require_kwargs_on_init +@dataclass(frozen=True) +class FeeSettings(LedgerObject): + """The model for the `FeeSettings` Ledger Object""" + + base_fee: Optional[str] = None + """ + The transaction cost of the "reference transaction" in drops of XRP as hexadecimal. + No longer used if XRPFees amendment is enabled. + """ + + reference_fee_units: Optional[int] = None + """ + The BaseFee translated into "fee units". This field is required. + """ + + reserve_base: Optional[int] = None + """ + The base reserve for an account in the XRP Ledger, as drops of XRP. + No longer used if XRPFees amendment is enabled. + """ + + reserve_increment: Optional[int] = None + """ + The incremental owner reserve for owning objects, as drops of XRP. + No longer used if XRPFees amendment is enabled. + """ + + base_fee_drops: Optional[str] = None + """ + The transaction cost of the "reference transaction" in drops of XRP. + """ + + reserve_base_drops: Optional[str] = None + """ + The base reserve for an account in the XRP Ledger, as drops of XRP. + """ + + reserve_increment_drops: Optional[str] = None + """ + The incremental owner reserve for owning objects, as drops of XRP. + """ + + ledger_entry_type: LedgerEntryType = field( + default=LedgerEntryType.FEE_SETTINGS, init=False + ) diff --git a/xrpl/models/ledger_objects/ledger_entry_type.py b/xrpl/models/ledger_objects/ledger_entry_type.py new file mode 100644 index 000000000..c19b3bce0 --- /dev/null +++ b/xrpl/models/ledger_objects/ledger_entry_type.py @@ -0,0 +1,29 @@ +"""The different ledger entry types""" + +from enum import Enum + + +class LedgerEntryType(str, Enum): + """The different ledger entry types""" + + ACCOUNT_ROOT = "AccountRoot" + AMENDMENTS = "Amendments" + AMM = "AMM" + BRIDGE = "Bridge" + CHECK = "Check" + DEPOSIT_PREAUTH = "DepositPreauth" + DID = "DID" + DIRECTORY_NODE = "DirectoryNode" + ESCROW = "Escrow" + FEE_SETTINGS = "FeeSettings" + LEDGER_HASHES = "LedgerHashes" + NEGATIVE_UNL = "NegativeUNL" + NFTOKEN_OFFER = "NFTokenOffer" + NFTOKEN_PAGE = "NFTokenPage" + OFFER = "Offer" + PAY_CHANNEL = "PayChannel" + RIPPLE_STATE = "RippleState" + SIGNER_LIST = "SignerList" + TICKET = "Ticket" + XCHAIN_OWNED_CLAIM_ID = "XChainOwnedClaimID" + XCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID = "XChainOwnedCreateAccountClaimID" diff --git a/xrpl/models/ledger_objects/ledger_hashes.py b/xrpl/models/ledger_objects/ledger_hashes.py new file mode 100644 index 000000000..66245129c --- /dev/null +++ b/xrpl/models/ledger_objects/ledger_hashes.py @@ -0,0 +1,42 @@ +"""Models for the Ledger Object `LedgerHashes`""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import List, Optional + +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_object import LedgerObject +from xrpl.models.required import REQUIRED +from xrpl.models.utils import require_kwargs_on_init + + +@require_kwargs_on_init +@dataclass(frozen=True) +class LedgerHashes(LedgerObject): + """The model for the `LedgerHashes` Ledger Object""" + + first_ledger_sequence: Optional[int] = None + """ + DEPRECATED Do not use. (The "recent hashes" object on Mainnet has the value 2 in + this field as a result of an old software bug. That value gets carried forward as + the "recent hashes" object is updated. New "previous history" objects do not have + this field, nor do "recent hashes" objects in parallel networks started with more + recent versions of rippled.) + """ + + last_ledger_sequence: Optional[int] = None + """ + The Ledger Index of the last entry in this object's `Hashes` array. + """ + + hashes: List[str] = REQUIRED # type: ignore + """ + An array of up to 256 ledger hashes. The contents depend on which sub-type of + LedgerHashes object this is. This field is required. + """ + + ledger_entry_type: LedgerEntryType = field( + default=LedgerEntryType.LEDGER_HASHES, + init=False, + ) diff --git a/xrpl/models/ledger_objects/ledger_object.py b/xrpl/models/ledger_objects/ledger_object.py new file mode 100644 index 000000000..a512af701 --- /dev/null +++ b/xrpl/models/ledger_objects/ledger_object.py @@ -0,0 +1,192 @@ +"""A model for Ledger Objects""" + +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any, Dict, Optional, Type, TypeVar + +from xrpl.models.base_model import BaseModel +from xrpl.models.exceptions import XRPLModelException +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.required import REQUIRED +from xrpl.models.utils import require_kwargs_on_init + +L = TypeVar("L", bound="LedgerObject") + + +@require_kwargs_on_init +@dataclass(frozen=True) +class LedgerObject(BaseModel): + """The base model for a Ledger Object.""" + + index: Optional[str] = None + """ + The unique ID for this ledger entry; either `index` or `LedgerIndex` is used. In + JSON, this field is represented with different names depending on the context and + API method. (Note, even though this is specified as "optional" in the code, every + ledger entry should have one unless it's legacy data from very early in the XRP + Ledger's history.) + """ + + ledger_index: Optional[str] = None + """ + The unique ID for this ledger entry; either `index` or `LedgerIndex` is used. In + JSON, this field is represented with different names depending on the context and + API method. (Note, even though this is specified as "optional" in the code, every + ledger entry should have one unless it's legacy data from very early in the XRP + Ledger's history.) + """ + + ledger_entry_type: LedgerEntryType = REQUIRED # type: ignore + """ + The type of ledger entry. Valid ledger entry types include AccountRoot, Offer, + RippleState, and others. This field is required. + """ + + flags: int = 0 + """ + Set of bit-flags for this ledger entry. + """ + + @classmethod + def from_dict(cls: Type[L], value: Dict[str, Any]) -> L: + """Derive the model from a dict. + + Args: + value: The dictionary to derive from. + + Returns: + L: The Ledger Object. + + Raises: + XRPLModelException: If there is no Ledger Object type is + provided or the type mismatches the constructor type. + """ + if cls.__name__ == "LedgerObject": + if "ledger_entry_type" not in value: + raise XRPLModelException( + "Ledger Object does not include ledger_entry_type." + ) + correct_type = cls.get_ledger_object_type(value["ledger_entry_type"]) + del value["ledger_entry_type"] + return correct_type.from_dict(value) # type: ignore + elif cls.__name__ in ["FinalFields", "PreviousFields", "NewFields"]: + if "ledger_entry_type" not in value: + raise XRPLModelException( + "Ledger Object does not include ledger_entry_type." + ) + correct_type = cls.get_md_ledger_object_type(value["ledger_entry_type"]) + del value["ledger_entry_type"] + return correct_type.from_dict(value) # type: ignore + else: + if "ledger_entry_type" in value: + ledger_entry_type = value["ledger_entry_type"] + if ( + cls.get_ledger_object_type(ledger_entry_type).__name__ + != cls.__name__ + and cls.get_md_ledger_object_type(ledger_entry_type).__name__ + != cls.__name__ + ): + raise XRPLModelException( + f"Using wrong constructor: using {cls.__name__} constructor " + f"with ledger object type {value['ledger_entry_type']}." + ) + value = {**value} + del value["ledger_entry_type"] + return super(LedgerObject, cls).from_dict(value) + + @classmethod + def get_ledger_object_type( + cls: Type[LedgerObject], ledger_object_type: str + ) -> Type[LedgerObject]: + """ + Gets the correct ledger object type. + + Args: + ledger_object_type: The ledger object type willing to get. + + Returns: + Type[LedgerObject]: The correct ledger object type. + + Raises: + XRPLModelException: If the Ledger Object type does not exist. + """ + import xrpl.models.ledger_objects as ledger_object_models + + ledger_object_types: Dict[str, Type[LedgerObject]] = { + lgr_obj.value: getattr(ledger_object_models, lgr_obj) + for lgr_obj in ledger_object_models.ledger_entry_type.LedgerEntryType + } + if ledger_object_type in ledger_object_types: + return ledger_object_types[ledger_object_type] + + raise XRPLModelException( + f"{ledger_object_type} is not a valid Ledger Object type." + ) + + @classmethod + def get_md_ledger_object_type( + cls: Type[LedgerObject], ledger_object_type: str + ) -> Type[LedgerObject]: + """ + Gets the ledger object type within fields prefixed with "MD and suffixed with + "Fields". + + Args: + ledger_object_type: The object type willing to get. + + Returns: + Type[LedgerObject]: The correct ledger object type. + + Raises: + XRPLModelException: If the Ledger Object type does not exist. + """ + import xrpl.models.ledger_objects as ledger_object_models + + ledger_object_types: Dict[str, Type[LedgerObject]] = { + lgr_obj.value: getattr(ledger_object_models, f"MD{lgr_obj}Fields") + for lgr_obj in ledger_object_models.ledger_entry_type.LedgerEntryType + } + if ledger_object_type in ledger_object_types: + return ledger_object_types[ledger_object_type] + + raise XRPLModelException( + f"{ledger_object_type} is not a valid Ledger Object type." + ) + + def __getitem__(self: LedgerObject, field_name: str) -> Any: + """ + Enable to get the fields like from a `dict` + + Args: + field_name: The field name to get. + + Returns: + Any: The field value. + """ + if field_name == self.__class__.__name__ or self.__class__.__name__ == "".join( + [word.capitalize() for word in field_name.split("_")] + ): + return self + return self.__getattribute__(field_name) + + +@require_kwargs_on_init +@dataclass(frozen=True) +class HasPreviousTxnID: + """ + A mixin for ledger objects that have `PreviousTxnID` and `PreviousTxnLgrSeq` + fields. + """ + + previous_txn_id: str = REQUIRED # type: ignore + """ + The identifying hash of the transaction that most recently modified this entry. + This field is required. + """ + + previous_txn_lgr_seq: int = REQUIRED # type: ignore + """ + The index of the ledger that contains the transaction that most recently modified + this entry. This field is required. + """ diff --git a/xrpl/models/ledger_objects/negative_unl.py b/xrpl/models/ledger_objects/negative_unl.py new file mode 100644 index 000000000..56b4dbf45 --- /dev/null +++ b/xrpl/models/ledger_objects/negative_unl.py @@ -0,0 +1,58 @@ +"""Models for the Ledger Object `NegativeUNL`""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import List, Optional + +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_object import LedgerObject +from xrpl.models.nested_model import NestedModel +from xrpl.models.required import REQUIRED +from xrpl.models.utils import require_kwargs_on_init + + +@require_kwargs_on_init +@dataclass(frozen=True) +class NegativeUNL(LedgerObject): + """The model for the `NegativeUNL` Ledger Object""" + + disabled_validators: Optional[List[DisabledValidator]] = None + """ + A list of `DisabledValidator` objects (see below), each representing a trusted + validator that is currently disabled. + """ + + validator_to_disable: Optional[str] = None + """ + The public key of a trusted validator that is scheduled to be disabled in the next + flag ledger. + """ + + validator_to_re_enable: Optional[str] = None + """ + The public key of a trusted validator in the Negative UNL that is scheduled to be + re-enabled in the next flag ledger. + """ + + ledger_entry_type: LedgerEntryType = field( + default=LedgerEntryType.NEGATIVE_UNL, init=False + ) + + +@require_kwargs_on_init +@dataclass(frozen=True) +class DisabledValidator(NestedModel): + """A model for the `DisabledValidator` object""" + + first_ledger_sequence: int = REQUIRED # type: ignore + """ + The ledger index when the validator was added to the Negative UNL. + This field is required. + """ + + public_key: str = REQUIRED # type: ignore + """ + The master public key of the validator, in hexadecimal. + This field is required. + """ diff --git a/xrpl/models/ledger_objects/nftoken_offer.py b/xrpl/models/ledger_objects/nftoken_offer.py new file mode 100644 index 000000000..c66a3a43d --- /dev/null +++ b/xrpl/models/ledger_objects/nftoken_offer.py @@ -0,0 +1,85 @@ +"""Models for the Ledger Object `NFTokenOffer`""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from enum import Enum +from typing import Optional + +from xrpl.models.base_model import BaseModel +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_object import HasPreviousTxnID, LedgerObject +from xrpl.models.required import REQUIRED +from xrpl.models.utils import require_kwargs_on_init + + +@require_kwargs_on_init +@dataclass(frozen=True) +class NFTokenOffer(LedgerObject, HasPreviousTxnID): + """The model for the `NFTokenOffer` Ledger Object""" + + amount: str = REQUIRED # type: ignore + """ + Amount expected or offered for the NFToken. If the token has the `lsfOnlyXRP` flag + set, the amount must be specified in XRP. Sell offers that specify assets other + than XRP must specify a non-zero amount. Sell offers that specify XRP can be 'free' + (that is, the Amount field can be equal to `"0"`). This field is required. + """ + + nftoken_id: str = REQUIRED # type: ignore + """ + The `NFTokenID` of the NFToken object referenced by this offer. This field is + required. + """ + + owner: str = REQUIRED # type: ignore + """ + Owner of the account that is creating and owns the offer. Only the current Owner of + an NFToken can create an offer to sell an NFToken, but any account can create an + offer to buy an NFToken. This field is required. + """ + + destination: Optional[str] = None + """ + The AccountID for which this offer is intended. If present, only that account can + accept the offer. + """ + + expiration: Optional[int] = None + """ + The time after which the offer is no longer active. The value is the number of + seconds since the Ripple Epoch. + """ + + owner_node: str = REQUIRED # type: ignore + """ + Internal bookkeeping, indicating the page inside the owner directory where this + token is being tracked. This field allows the efficient deletion of offers. + """ + + nftoken_offer_node: str = REQUIRED # type: ignore + """ + Internal bookkeeping, indicating the page inside the token buy or sell offer + directory, as appropriate, where this token is being tracked. This field allows the + efficient deletion of offers. + """ + + ledger_entry_type: LedgerEntryType = field( + default=LedgerEntryType.NFTOKEN_OFFER, + init=False, + ) + + +@require_kwargs_on_init +@dataclass(frozen=True) +class NFToken(BaseModel): # + """A model for the `NFToken` object""" + + nftoken_id: str = REQUIRED # type: ignore + uri: str = REQUIRED # type: ignore + + +class NFTokenOfferFlags(Enum): + """The flags for the `NFTokenOffer` Ledger Object""" + + LSF_SELL_NFTOKEN = 0x00000001 diff --git a/xrpl/models/ledger_objects/nftoken_page.py b/xrpl/models/ledger_objects/nftoken_page.py new file mode 100644 index 000000000..d5bcfa6e6 --- /dev/null +++ b/xrpl/models/ledger_objects/nftoken_page.py @@ -0,0 +1,42 @@ +"""Models for the Ledger Object `NFTokenPage`""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import List, Optional + +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_object import HasPreviousTxnID, LedgerObject +from xrpl.models.ledger_objects.nftoken_offer import NFToken +from xrpl.models.required import REQUIRED +from xrpl.models.utils import require_kwargs_on_init + + +@require_kwargs_on_init +@dataclass(frozen=True) +class NFTokenPage(LedgerObject, HasPreviousTxnID): + """The model for the `NFTokenPage` Ledger Object""" + + next_page_min: Optional[str] = None + """ + The locator of the next page, if any. Details about this field and how it should be + used are outlined below. + """ + + previous_page_min: Optional[str] = None + """ + The locator of the previous page, if any. Details about this field and how it + should be used are outlined below. + """ + + nftokens: List[NFToken] = REQUIRED # type: ignore + """ + The collection of NFToken objects contained in this NFTokenPage object. This + specification places an upper bound of 32 NFToken objects per page. Objects are + sorted from low to high with the NFTokenID used as the sorting parameter. + """ + + ledger_entry_type: LedgerEntryType = field( + default=LedgerEntryType.NFTOKEN_PAGE, + init=False, + ) diff --git a/xrpl/models/ledger_objects/offer.py b/xrpl/models/ledger_objects/offer.py new file mode 100644 index 000000000..0fea1778a --- /dev/null +++ b/xrpl/models/ledger_objects/offer.py @@ -0,0 +1,77 @@ +"""Models for the Ledger Object `Offer`""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from enum import Enum +from typing import Optional, Union + +from xrpl.models.amounts.issued_currency_amount import IssuedCurrencyAmount +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_object import HasPreviousTxnID, LedgerObject +from xrpl.models.required import REQUIRED +from xrpl.models.utils import require_kwargs_on_init + + +@require_kwargs_on_init +@dataclass(frozen=True) +class Offer(LedgerObject, HasPreviousTxnID): + """The model for the `Offer` Ledger Object""" + + account: str = REQUIRED # type: ignore + """ + The address of the account that owns this Offer. This field is required. + """ + + book_directory: str = REQUIRED # type: ignore + """ + The ID of the Offer Directory that links to this Offer. This field is required. + """ + + book_node: str = REQUIRED # type: ignore + """ + A hint indicating which page of the offer directory links to this entry, in case + the directory consists of multiple pages. This field is required. + """ + + expiration: Optional[int] = None + """ + Indicates the time after which this Offer is considered unfunded. See Specifying + Time for details. + """ + + owner_node: str = REQUIRED # type: ignore + """ + A hint indicating which page of the owner directory links to this entry, in case + the directory consists of multiple pages. This field is required. + """ + + sequence: int = REQUIRED # type: ignore + """ + The `Sequence` value of the `OfferCreate` transaction that created this offer. Used + in combination with the `Account` to identify this offer. This field is required. + """ + + taker_gets: Union[str, IssuedCurrencyAmount] = REQUIRED # type: ignore + """ + The remaining amount and type of currency being provided by the `Offer` creator. + This field is required. + """ + + taker_pays: Union[str, IssuedCurrencyAmount] = REQUIRED # type: ignore + """ + The remaining amount and type of currency requested by the `Offer` creator. + This field is required. + """ + + ledger_entry_type: LedgerEntryType = field( + default=LedgerEntryType.OFFER, + init=False, + ) + + +class OfferFlag(Enum): + """The flags for the `Offer` Ledger Object""" + + LSF_PASSIVE = 0x00010000 + LSF_SELL = 0x00020000 diff --git a/xrpl/models/ledger_objects/pay_channel.py b/xrpl/models/ledger_objects/pay_channel.py new file mode 100644 index 000000000..eaa434d38 --- /dev/null +++ b/xrpl/models/ledger_objects/pay_channel.py @@ -0,0 +1,110 @@ +"""Models for the Ledger Object `PayChannel`""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Optional + +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_object import HasPreviousTxnID, LedgerObject +from xrpl.models.required import REQUIRED +from xrpl.models.utils import require_kwargs_on_init + + +@require_kwargs_on_init +@dataclass(frozen=True) +class PayChannel(LedgerObject, HasPreviousTxnID): + """The model for the `PayChannel` Ledger Object""" + + account: str = REQUIRED # type: ignore + """ + The source address that owns this payment channel. This comes from the sending + address of the transaction that created the channel. This field is required. + """ + + amount: str = REQUIRED # type: ignore + """ + Total XRP, in drops, that has been allocated to this channel. This includes XRP + that has been paid to the destination address. This is initially set by the + transaction that created the channel and can be increased if the source address + sends a `PaymentChannelFund` transaction. This field is required. + """ + + balance: str = REQUIRED # type: ignore + """ + Total XRP, in drops, already paid out by the channel. The difference between this + value and the `Amount` field is how much XRP can still be paid to the destination + address with PaymentChannelClaim transactions. If the channel closes, the remaining + difference is returned to the source address. This field is required. + """ + + destination: str = REQUIRED # type: ignore + """ + The destination address for this payment channel. While the payment channel is open, + this address is the only one that can receive XRP from the channel. This comes from + the `Destination` field of the transaction that created the channel. This field is + required. + """ + + destination_tag: Optional[int] = None + """ + An arbitrary tag to further specify the destination for this payment channel, such + as a hosted recipient at the destination address. + """ + + destination_node: Optional[str] = None + """ + A hint indicating which page of the destination's owner directory links to this + entry, in case the directory consists of multiple pages. Omitted on payment + channels created before enabling the fixPayChanRecipientOwnerDir amendment. + """ + + owner_node: str = REQUIRED # type: ignore + """ + A hint indicating which page of the source address's owner directory links to this + entry, in case the directory consists of multiple pages. This field is required. + """ + + public_key: str = REQUIRED # type: ignore + """ + Public key, in hexadecimal, of the key pair that can be used to sign claims against + this channel. This can be any valid secp256k1 or Ed25519 public key. This is set by + the transaction that created the channel and must match the public key used in + claims against the channel. The channel source address can also send XRP from this + channel to the destination without signed claims. This field is required. + """ + + settle_delay: int = REQUIRED # type: ignore + """ + Number of seconds the source address must wait to close the channel if it still has + any XRP in it. Smaller values mean that the destination address has less time to + redeem any outstanding claims after the source address requests to close the + channel. Can be any value that fits in a 32-bit unsigned integer (0 to 2^32-1). + This is set by the transaction that creates the channel. This field is required. + """ + + expiration: Optional[int] = None + """ + The mutable expiration time for this payment channel, in seconds since the Ripple + Epoch. The channel is expired if this value is present and smaller than the + previous ledger's close_time field. See Channel Expiration for more details. + """ + + cancel_after: Optional[int] = None + """ + The immutable expiration time for this payment channel, in seconds since the Ripple + Epoch. This channel is expired if this value is present and smaller than the + previous ledger's close_time field. This is optionally set by the transaction that + created the channel, and cannot be changed. This field is required. + """ + + source_tag: Optional[int] = None + """ + An arbitrary tag to further specify the source for this payment channel, such as a + hosted recipient at the owner's address. + """ + + ledger_entry_type: LedgerEntryType = field( + default=LedgerEntryType.PAY_CHANNEL, + init=False, + ) diff --git a/xrpl/models/ledger_objects/ripple_state.py b/xrpl/models/ledger_objects/ripple_state.py new file mode 100644 index 000000000..059013ae2 --- /dev/null +++ b/xrpl/models/ledger_objects/ripple_state.py @@ -0,0 +1,100 @@ +"""Models for the Ledger Object `RippleState`""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from enum import Enum +from typing import Optional + +from xrpl.models.amounts.issued_currency_amount import IssuedCurrencyAmount +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_object import HasPreviousTxnID, LedgerObject +from xrpl.models.required import REQUIRED +from xrpl.models.utils import require_kwargs_on_init + + +@require_kwargs_on_init +@dataclass(frozen=True) +class RippleState(LedgerObject, HasPreviousTxnID): + """The model for the `RippleState` Ledger Object""" + + balance: IssuedCurrencyAmount = REQUIRED # type: ignore + """ + The balance of the trust line, from the perspective of the low account. A negative + balance indicates that the high account holds tokens issued by the low account. The + issuer in this is always set to the neutral value ACCOUNT_ONE. This field is + required. + """ + + high_limit: IssuedCurrencyAmount = REQUIRED # type: ignore + """ + The limit that the high account has set on the trust line. The `issuer` is the + address of the high account that set this limit. This field is required. + """ + + low_limit: IssuedCurrencyAmount = REQUIRED # type: ignore + """ + The limit that the low account has set on the trust line. The `issuer` is the + address of the low account that set this limit. This field is required. + """ + + high_node: Optional[str] = None + """ + (Omitted in some historical ledgers) A hint indicating which page of the high + account's owner directory links to this entry, in case the directory consists of + multiple pages. + """ + + high_quality_in: Optional[int] = None + """ + The inbound quality set by the high account, as an integer in the implied ratio + `HighQualityIn`:1,000,000,000. As a special case, the value 0 is equivalent to 1 + billion, or face value. + """ + + high_quality_out: Optional[int] = None + """ + The outbound quality set by the high account, as an integer in the implied ratio + `HighQualityOut`:1,000,000,000. As a special case, the value 0 is equivalent to 1 + billion, or face value. + """ + + low_node: Optional[str] = None + """ + (Omitted in some historical ledgers) A hint indicating which page of the low + account's owner directory links to this entry, in case the directory consists of + multiple pages. + """ + + low_quality_in: Optional[int] = None + """ + The inbound quality set by the low account, as an integer in the implied ratio + `LowQualityIn`:1,000,000,000. As a special case, the value 0 is equivalent to 1 + billion, or face value. + """ + + low_quality_out: Optional[int] = None + """ + The outbound quality set by the low account, as an integer in the implied ratio + `LowQualityOut`:1,000,000,000. As a special case, the value 0 is equivalent to 1 + billion, or face value. + """ + + ledger_entry_type: LedgerEntryType = field( + default=LedgerEntryType.RIPPLE_STATE, + init=False, + ) + + +class RippleStateFlag(Enum): + """The flags for the `RippleState` Ledger Object""" + + LSF_LOW_RESERVE = 0x00010000 + LSF_HIGH_RESERVE = 0x00020000 + LSF_LOW_AUTH = 0x00040000 + LSF_HIGH_AUTH = 0x00080000 + LSF_LOW_NO_RIPPLE = 0x00100000 + LSF_HIGH_NO_RIPPLE = 0x00200000 + LSF_LOW_FREEZE = 0x00400000 + LSF_HIGH_FREEZE = 0x00800000 + LSF_AMM_NODE = 0x01000000 diff --git a/xrpl/models/ledger_objects/signer_list.py b/xrpl/models/ledger_objects/signer_list.py new file mode 100644 index 000000000..519f39b45 --- /dev/null +++ b/xrpl/models/ledger_objects/signer_list.py @@ -0,0 +1,55 @@ +"""Models for the Ledger Object `SignerList`""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from enum import Enum +from typing import List + +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_object import HasPreviousTxnID, LedgerObject +from xrpl.models.required import REQUIRED +from xrpl.models.transactions.signer_list_set import SignerEntry +from xrpl.models.utils import require_kwargs_on_init + + +@require_kwargs_on_init +@dataclass(frozen=True) +class SignerList(LedgerObject, HasPreviousTxnID): + """The model for the `SignerList` Ledger Object""" + + owner_node: str = REQUIRED # type: ignore + """ + A hint indicating which page of the owner directory links to this object, in case + the directory consists of multiple pages. This field is required. + """ + + signer_entries: List[SignerEntry] = REQUIRED # type: ignore + """ + An array of Signer Entry objects representing the parties who are part of this + signer list. This field is required. + """ + + signer_list_id: int = REQUIRED # type: ignore + """ + An ID for this signer list. Currently always set to 0. If a future amendment allows + multiple signer lists for an account, this may change. This field is required. + """ + + signer_quorum: int = REQUIRED # type: ignore + """ + A target number for signer weights. To produce a valid signature for the owner of + this SignerList, the signers must provide valid signatures whose weights sum to + this value or more. This field is required. + """ + + ledger_entry_type: LedgerEntryType = field( + default=LedgerEntryType.SIGNER_LIST, + init=False, + ) + + +class SignerListFlag(Enum): + """The flags for the `SignerList` Ledger Object""" + + LSF_ONE_OWNER_COUNT = 0x00010000 diff --git a/xrpl/models/ledger_objects/ticket.py b/xrpl/models/ledger_objects/ticket.py new file mode 100644 index 000000000..ec455e5e1 --- /dev/null +++ b/xrpl/models/ledger_objects/ticket.py @@ -0,0 +1,37 @@ +"""Models for the Ledger Object `Ticket`""" + +from __future__ import annotations + +from dataclasses import dataclass, field + +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_object import HasPreviousTxnID, LedgerObject +from xrpl.models.required import REQUIRED +from xrpl.models.utils import require_kwargs_on_init + + +@require_kwargs_on_init +@dataclass(frozen=True) +class Ticket(LedgerObject, HasPreviousTxnID): + """The model for the `Ticket` Ledger Object""" + + account: str = REQUIRED # type: ignore + """ + The account that owns this Ticket. This field is required. + """ + + owner_node: str = REQUIRED # type: ignore + """ + A hint indicating which page of the owner directory links to this entry, in case + the directory consists of multiple pages. This field is required. + """ + + ticket_sequence: int = REQUIRED # type: ignore + """ + The Sequence Number this Ticket sets aside. This field is required. + """ + + ledger_entry_type: LedgerEntryType = field( + default=LedgerEntryType.TICKET, + init=False, + ) diff --git a/xrpl/models/ledger_objects/xchain_owned_claim_id.py b/xrpl/models/ledger_objects/xchain_owned_claim_id.py new file mode 100644 index 000000000..95750ef42 --- /dev/null +++ b/xrpl/models/ledger_objects/xchain_owned_claim_id.py @@ -0,0 +1,117 @@ +"""Models for the Ledger Object `XChainOwnedClaimID`""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import List, Optional, Union + +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_object import HasPreviousTxnID, LedgerObject +from xrpl.models.nested_model import NestedModel +from xrpl.models.required import REQUIRED +from xrpl.models.utils import require_kwargs_on_init +from xrpl.models.xchain_bridge import XChainBridge + + +@require_kwargs_on_init +@dataclass(frozen=True) +class XChainOwnedClaimID(LedgerObject, HasPreviousTxnID): + """The model for the `XChainOwnedClaimID` Ledger Object""" + + account: str = REQUIRED # type: ignore + """ + The account that owns this object. This field is required. + """ + + ledger_index: str = REQUIRED # type: ignore + """ + The ledger index is a hash of a unique prefix for `XChainOwnedClaimID`s, the actual + `XChainClaimID` value, and the fields in `XChainBridge`. This field is required. + """ + + other_chain_source: str = REQUIRED # type: ignore + """ + The account that must send the corresponding `XChainCommit` on the source chain. The + destination may be specified in the `XChainCommit` transaction, which means that if + the `OtherChainSource` isn't specified, another account can try to specify a + different destination and steal the funds. This also allows tracking only a single + set of signatures, since we know which account will send the `XChainCommit` + transaction. This field is required. + """ + + signature_reward: str = REQUIRED # type: ignore + """ + The total amount to pay the witness servers for their signatures. It must be at + least the value of `SignatureReward` in the `Bridge` ledger object. + This field is required. + """ + + xchain_bridge: XChainBridge = REQUIRED # type: ignore + """ + The door accounts and assets of the bridge this object correlates to. + This field is required. + """ + + xchain_claim_attestations: List[XChainClaimProofSig] = REQUIRED # type: ignore + """ + Attestations collected from the witness servers. This includes the parameters + needed to recreate the message that was signed, including the amount, which chain + (locking or issuing), optional destination, and reward account for that signature. + This field is required. + """ + + xchain_claim_id: Union[int, str] = REQUIRED # type: ignore + """ + The unique sequence number for a cross-chain transfer. This field is required. + """ + + owner_node: str = REQUIRED # type: ignore + """ + A hint indicating which page of the sender's owner directory links to this entry, + in case the directory consists of multiple pages. + """ + + ledger_entry_type: LedgerEntryType = field( + default=LedgerEntryType.XCHAIN_OWNED_CLAIM_ID, + init=False, + ) + + +@require_kwargs_on_init +@dataclass(frozen=True) +class XChainClaimProofSig(NestedModel): + """A model for the `XChainClaimProofSig` object""" + + amount: str = REQUIRED # type: ignore + """ + The amount to claim in the `XChainCommit` transaction on the destination chain. + This field is required. + """ + + attestation_reward_account: str = REQUIRED # type: ignore + """ + The account that should receive this signer's share of the `SignatureReward`. + This field is required. + """ + + attestation_signer_account: str = REQUIRED # type: ignore + """ + The account on the door account's signer list that is signing the transaction. + This field is required. + """ + + destination: Optional[str] = None + """ + The destination account for the funds on the destination chain. + """ + + public_key: str = REQUIRED # type: ignore + """ + The public key used to verify the signature. This field is required. + """ + + was_locking_chain_send: int = REQUIRED # type: ignore + """ + A boolean representing the chain where the event occurred. + This field is required. + """ diff --git a/xrpl/models/ledger_objects/xchain_owned_create_account_claim_id.py b/xrpl/models/ledger_objects/xchain_owned_create_account_claim_id.py new file mode 100644 index 000000000..aaff0bdcf --- /dev/null +++ b/xrpl/models/ledger_objects/xchain_owned_create_account_claim_id.py @@ -0,0 +1,111 @@ +"""Models for the Ledger Object `XChainOwnedCreateAccountClaimID`""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import List, Optional, Union + +from xrpl.models.ledger_objects.ledger_entry_type import LedgerEntryType +from xrpl.models.ledger_objects.ledger_object import HasPreviousTxnID, LedgerObject +from xrpl.models.nested_model import NestedModel +from xrpl.models.required import REQUIRED +from xrpl.models.utils import require_kwargs_on_init +from xrpl.models.xchain_bridge import XChainBridge + + +@require_kwargs_on_init +@dataclass(frozen=True) +class XChainOwnedCreateAccountClaimID(LedgerObject, HasPreviousTxnID): + """The model for the `XChainOwnedCreateAccountClaimID` Ledger Object""" + + account: str = REQUIRED # type: ignore + """ + The account that owns this object. This field is required. + """ + + ledger_index: str = REQUIRED # type: ignore + """ + The ledger index is a hash of a unique prefix for `XChainOwnedClaimID`s, the actual + `XChainClaimID` value, and the fields in `XChainBridge`. This field is required. + """ + + xchain_account_create_count: Union[int, str] = REQUIRED # type: ignore + """ + An integer that determines the order that accounts created through cross-chain + transfers must be performed. Smaller numbers must execute before larger numbers. + This field is required. + """ + + xchain_bridge: XChainBridge = REQUIRED # type: ignore + """ + The door accounts and assets of the bridge this object correlates to. + This field is required. + """ + + xchain_create_account_attestations: List[ + XChainCreateAccountProofSig + ] = REQUIRED # type: ignore + """ + Attestations collected from the witness servers. This includes the parameters + needed to recreate the message that was signed, including the amount, which chain + (locking or issuing), optional destination, and reward account for that signature. + This field is required. + """ + + owner_node: str = REQUIRED # type: ignore + """ + A hint indicating which page of the sender's owner directory links to this entry, + in case the directory consists of multiple pages. This field is required. + """ + + ledger_entry_type: LedgerEntryType = field( + default=LedgerEntryType.XCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID, + init=False, + ) + + +@require_kwargs_on_init +@dataclass(frozen=True) +class XChainCreateAccountProofSig(NestedModel): + """A model for the `XChainCreateAccountProofSig` object""" + + amount: str = REQUIRED # type: ignore + """ + The amount to claim in the `XChainCommit` transaction on the destination chain. + This field is required. + """ + + attestation_reward_account: str = REQUIRED # type: ignore + """ + The account that should receive this signer's share of the `SignatureReward`. + This field is required. + """ + + attestation_signer_account: str = REQUIRED # type: ignore + """ + The account on the door account's signer list that is signing the transaction. + This field is required. + """ + + destination: Optional[str] = None + """ + The destination account for the funds on the destination chain. + """ + + public_key: str = REQUIRED # type: ignore + """ + The public key used to verify the signature. This field is required. + """ + + signature_reward: str = REQUIRED # type: ignore + """ + The total amount to pay the witness servers for their signatures. It must be at + least the value of `SignatureReward` in the `Bridge` ledger object. + This field is required. + """ + + was_locking_chain_send: int = REQUIRED # type: ignore + """ + A boolean representing the chain where the event occurred. + This field is required. + """