├── .ci-config └── rippled.cfg ├── .coderabbit.yaml ├── .flake8 ├── .github ├── dependabot.yml ├── pull_request_template.md └── workflows │ ├── faucet_test.yml │ ├── integration_test.yml │ ├── publish_to_pypi.yml │ ├── snippet_test.yml │ └── unit_test.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .readthedocs.yaml ├── .vscode ├── extensions.json └── settings.json ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── MANIFEST.in ├── README.md ├── docs ├── Makefile ├── conf.py ├── index.rst ├── make.bat └── source │ ├── modules.rst │ ├── snippets.rst │ ├── xrpl.account.rst │ ├── xrpl.asyncio.account.rst │ ├── xrpl.asyncio.clients.rst │ ├── xrpl.asyncio.ledger.rst │ ├── xrpl.asyncio.rst │ ├── xrpl.asyncio.transaction.rst │ ├── xrpl.asyncio.wallet.rst │ ├── xrpl.clients.rst │ ├── xrpl.core.addresscodec.rst │ ├── xrpl.core.binarycodec.binary_wrappers.rst │ ├── xrpl.core.binarycodec.definitions.rst │ ├── xrpl.core.binarycodec.rst │ ├── xrpl.core.binarycodec.types.rst │ ├── xrpl.core.keypairs.rst │ ├── xrpl.core.rst │ ├── xrpl.ledger.rst │ ├── xrpl.models.amounts.rst │ ├── xrpl.models.currencies.rst │ ├── xrpl.models.requests.rst │ ├── xrpl.models.rst │ ├── xrpl.models.transactions.pseudo_transactions.rst │ ├── xrpl.models.transactions.rst │ ├── xrpl.models.transactions.types.rst │ ├── xrpl.rst │ ├── xrpl.transaction.rst │ ├── xrpl.utils.rst │ ├── xrpl.utils.txn_parser.rst │ ├── xrpl.utils.txn_parser.utils.rst │ └── xrpl.wallet.rst ├── mypy.ini ├── poetry.lock ├── poetry.toml ├── py.typed ├── pyproject.toml ├── snippets ├── README.md ├── get_transaction.py ├── multisign.py ├── partial_payment.py ├── paths.py ├── send_escrow.py ├── set_regular_key.py └── submit_payment.py ├── tests ├── __init__.py ├── faucet │ └── test_faucet_wallet.py ├── integration │ ├── __init__.py │ ├── clients │ │ ├── __init__.py │ │ └── test_json_rpc_client.py │ ├── integration_test_case.py │ ├── it_utils.py │ ├── reqs │ │ ├── __init__.py │ │ ├── test_account_info.py │ │ ├── test_account_objects.py │ │ ├── test_account_tx.py │ │ ├── test_amm_info.py │ │ ├── test_book_offers.py │ │ ├── test_channel_verify.py │ │ ├── test_feature.py │ │ ├── test_generic_request.py │ │ ├── test_ledger.py │ │ ├── test_no_ripple_check.py │ │ ├── test_ripple_path_find.py │ │ ├── test_server_definitions.py │ │ ├── test_server_info.py │ │ ├── test_simulate.py │ │ ├── test_submit_multisigned.py │ │ ├── test_submit_only.py │ │ ├── test_subscribe.py │ │ └── test_tx.py │ ├── reusable_values.py │ ├── sugar │ │ ├── __init__.py │ │ ├── test_account.py │ │ ├── test_ledger.py │ │ └── test_transaction.py │ └── transactions │ │ ├── __init__.py │ │ ├── test_account_delete.py │ │ ├── test_account_set.py │ │ ├── test_amm_bid.py │ │ ├── test_amm_clawback.py │ │ ├── test_amm_create.py │ │ ├── test_amm_deposit.py │ │ ├── test_amm_vote.py │ │ ├── test_amm_withdraw.py │ │ ├── test_batch.py │ │ ├── test_check_cancel.py │ │ ├── test_check_cash.py │ │ ├── test_check_create.py │ │ ├── test_clawback.py │ │ ├── test_credential.py │ │ ├── test_delegate_set.py │ │ ├── test_delete_oracle.py │ │ ├── test_deposit_preauth.py │ │ ├── test_did_delete.py │ │ ├── test_did_set.py │ │ ├── test_escrow_cancel.py │ │ ├── test_escrow_create.py │ │ ├── test_escrow_finish.py │ │ ├── test_mptoken_authorize.py │ │ ├── test_mptoken_issuance_create.py │ │ ├── test_mptoken_issuance_destroy.py │ │ ├── test_mptoken_issuance_set.py │ │ ├── test_offer_cancel.py │ │ ├── test_offer_create.py │ │ ├── test_payment.py │ │ ├── test_payment_channel_claim.py │ │ ├── test_payment_channel_create.py │ │ ├── test_payment_channel_fund.py │ │ ├── test_permissioned_domain.py │ │ ├── test_set_oracle.py │ │ ├── test_set_regular_key.py │ │ ├── test_signer_list_set.py │ │ ├── test_ticket_create.py │ │ ├── test_trust_set.py │ │ ├── test_xchain_account_create_commit.py │ │ ├── test_xchain_add_account_create_attestation.py │ │ ├── test_xchain_add_claim_attestation.py │ │ ├── test_xchain_claim.py │ │ ├── test_xchain_commit.py │ │ ├── test_xchain_create_bridge.py │ │ ├── test_xchain_create_claim_id.py │ │ └── test_xchain_modify_bridge.py └── unit │ ├── __init__.py │ ├── asyn │ ├── __init__.py │ ├── ledger │ │ ├── __init__.py │ │ └── test_calculate_fee_dynamically.py │ └── wallet │ │ ├── __init__.py │ │ ├── test_main.py │ │ └── test_wallet.py │ ├── core │ ├── __init__.py │ ├── addresscodec │ │ ├── __init__.py │ │ ├── test_codec.py │ │ ├── test_main.py │ │ └── test_main_test_cases.py │ ├── binarycodec │ │ ├── __init__.py │ │ ├── fixtures │ │ │ ├── data │ │ │ │ ├── codec-fixtures.json │ │ │ │ ├── data-driven-tests.json │ │ │ │ └── x-codec-fixtures.json │ │ │ └── data_driven_fixtures.py │ │ ├── test_binary_parser.py │ │ ├── test_binary_serializer.py │ │ ├── test_definition_service.py │ │ ├── test_field_id_codec.py │ │ ├── test_main.py │ │ └── types │ │ │ ├── __init__.py │ │ │ ├── test_account_id.py │ │ │ ├── test_amount.py │ │ │ ├── test_blob.py │ │ │ ├── test_currency.py │ │ │ ├── test_hash_types.py │ │ │ ├── test_issue.py │ │ │ ├── test_path_set.py │ │ │ ├── test_serialized_dict.py │ │ │ ├── test_serialized_list.py │ │ │ ├── test_serialized_type.py │ │ │ ├── test_uint.py │ │ │ └── test_vector256.py │ └── keypairs │ │ ├── __init__.py │ │ └── test_main.py │ ├── models │ ├── __init__.py │ ├── amounts │ │ ├── __init__.py │ │ └── test_issued_currency_amount.py │ ├── currencies │ │ ├── __init__.py │ │ ├── test_issued_currency.py │ │ ├── test_mpt_currency.py │ │ └── test_xrp.py │ ├── requests │ │ ├── __init__.py │ │ ├── test_amm_info.py │ │ ├── test_channel_authorize.py │ │ ├── test_deposit_authorized.py │ │ ├── test_get_aggregate_price.py │ │ ├── test_ledger_entry.py │ │ ├── test_requests.py │ │ ├── test_sign.py │ │ ├── test_simulate.py │ │ └── test_tx.py │ ├── test_base_model.py │ ├── test_response.py │ ├── test_utils.py │ ├── transactions │ │ ├── __init__.py │ │ ├── test_account_delete.py │ │ ├── test_account_set.py │ │ ├── test_amm_bid.py │ │ ├── test_amm_clawback.py │ │ ├── test_amm_create.py │ │ ├── test_amm_delete.py │ │ ├── test_amm_deposit.py │ │ ├── test_amm_vote.py │ │ ├── test_amm_withdraw.py │ │ ├── test_batch.py │ │ ├── test_better_transaction_flags.py │ │ ├── test_check_cash.py │ │ ├── test_clawback.py │ │ ├── test_credential_accept.py │ │ ├── test_credential_create.py │ │ ├── test_credential_delete.py │ │ ├── test_delegate_set.py │ │ ├── test_deposit_preauth.py │ │ ├── test_did_delete.py │ │ ├── test_did_set.py │ │ ├── test_escrow_create.py │ │ ├── test_escrow_finish.py │ │ ├── test_mptoken_authorize.py │ │ ├── test_mptoken_issuance_create.py │ │ ├── test_mptoken_issuance_destroy.py │ │ ├── test_mptoken_issuance_set.py │ │ ├── test_nftoken_accept_offer.py │ │ ├── test_nftoken_cancel_offer.py │ │ ├── test_nftoken_create_offer.py │ │ ├── test_nftoken_mint.py │ │ ├── test_nftoken_modify.py │ │ ├── test_oracle_delete.py │ │ ├── test_oracle_set.py │ │ ├── test_payment.py │ │ ├── test_payment_channel_claim.py │ │ ├── test_permissioned_domain_delete.py │ │ ├── test_permissioned_domain_set.py │ │ ├── test_pseudo_transactions.py │ │ ├── test_signer_list_set.py │ │ ├── test_transaction.py │ │ ├── test_xchain_account_create_commit.py │ │ ├── test_xchain_claim.py │ │ ├── test_xchain_create_bridge.py │ │ ├── test_xchain_create_claim_id.py │ │ └── test_xchain_modify_bridge.py │ └── x-codec-fixtures.json │ ├── transaction │ ├── __init__.py │ └── test_batch_signers.py │ ├── utils │ ├── __init__.py │ ├── test_get_nftoken_id.py │ ├── test_get_xchain_claim_id.py │ ├── test_parse_nftoken_id.py │ ├── test_str_conversions.py │ ├── test_time_conversions.py │ ├── test_xrp_conversions.py │ └── txn_parser │ │ ├── __init__.py │ │ ├── test_get_balance_changes.py │ │ ├── test_get_final_balances.py │ │ ├── test_get_order_book_changes.py │ │ └── transaction_jsons │ │ ├── XChainCreateClaimID.json │ │ ├── XChainCreateClaimID2.json │ │ ├── nftokenmint_response1.json │ │ ├── nftokenmint_response2.json │ │ ├── offer_cancelled.json │ │ ├── offer_created.json │ │ ├── offer_partially_filled_and_filled.json │ │ ├── offer_with_expiration.json │ │ ├── payment_iou.json │ │ ├── payment_iou_destination_no_balance.json │ │ ├── payment_iou_multipath.json │ │ ├── payment_iou_redeem.json │ │ ├── payment_iou_redeem_then_issue.json │ │ ├── payment_iou_spend_full_balance.json │ │ ├── payment_xrp_create_account.json │ │ ├── trustline_create.json │ │ ├── trustline_delete.json │ │ ├── trustline_set_limit.json │ │ ├── trustline_set_limit2.json │ │ └── trustline_set_limit_zero.json │ └── wallet │ ├── __init__.py │ └── test_wallet.py ├── tools ├── generate_definitions.py └── generate_tx_models.py └── xrpl ├── __init__.py ├── account ├── __init__.py ├── main.py ├── py.typed └── transaction_history.py ├── asyncio ├── __init__.py ├── account │ ├── __init__.py │ ├── main.py │ ├── py.typed │ └── transaction_history.py ├── clients │ ├── __init__.py │ ├── async_client.py │ ├── async_json_rpc_client.py │ ├── async_websocket_client.py │ ├── client.py │ ├── exceptions.py │ ├── json_rpc_base.py │ ├── py.typed │ ├── utils.py │ └── websocket_base.py ├── ledger │ ├── __init__.py │ ├── main.py │ ├── py.typed │ └── utils.py ├── py.typed ├── transaction │ ├── __init__.py │ ├── main.py │ ├── py.typed │ └── reliable_submission.py └── wallet │ ├── __init__.py │ ├── py.typed │ └── wallet_generation.py ├── clients ├── __init__.py ├── json_rpc_client.py ├── py.typed ├── sync_client.py └── websocket_client.py ├── constants.py ├── core ├── __init__.py ├── addresscodec │ ├── __init__.py │ ├── codec.py │ ├── exceptions.py │ ├── main.py │ ├── py.typed │ └── utils.py ├── binarycodec │ ├── __init__.py │ ├── binary_wrappers │ │ ├── __init__.py │ │ ├── binary_parser.py │ │ └── binary_serializer.py │ ├── definitions │ │ ├── __init__.py │ │ ├── definitions.json │ │ ├── definitions.py │ │ ├── field_header.py │ │ ├── field_info.py │ │ └── field_instance.py │ ├── exceptions.py │ ├── field_id_codec.py │ ├── main.py │ ├── py.typed │ └── types │ │ ├── __init__.py │ │ ├── account_id.py │ │ ├── amount.py │ │ ├── blob.py │ │ ├── currency.py │ │ ├── hash.py │ │ ├── hash128.py │ │ ├── hash160.py │ │ ├── hash192.py │ │ ├── hash256.py │ │ ├── issue.py │ │ ├── path_set.py │ │ ├── serialized_type.py │ │ ├── st_array.py │ │ ├── st_object.py │ │ ├── uint.py │ │ ├── uint16.py │ │ ├── uint32.py │ │ ├── uint64.py │ │ ├── uint8.py │ │ ├── vector256.py │ │ └── xchain_bridge.py ├── keypairs │ ├── __init__.py │ ├── crypto_implementation.py │ ├── ed25519.py │ ├── exceptions.py │ ├── helpers.py │ ├── main.py │ ├── py.typed │ └── secp256k1.py └── py.typed ├── ledger ├── __init__.py ├── main.py └── py.typed ├── models ├── __init__.py ├── amounts │ ├── __init__.py │ ├── amount.py │ ├── issued_currency_amount.py │ ├── mpt_amount.py │ └── py.typed ├── auth_account.py ├── base_model.py ├── currencies │ ├── __init__.py │ ├── currency.py │ ├── issued_currency.py │ ├── mpt_currency.py │ ├── py.typed │ └── xrp.py ├── exceptions.py ├── flags.py ├── nested_model.py ├── path.py ├── py.typed ├── requests │ ├── __init__.py │ ├── account_channels.py │ ├── account_currencies.py │ ├── account_info.py │ ├── account_lines.py │ ├── account_nfts.py │ ├── account_objects.py │ ├── account_offers.py │ ├── account_tx.py │ ├── amm_info.py │ ├── book_offers.py │ ├── channel_authorize.py │ ├── channel_verify.py │ ├── deposit_authorized.py │ ├── feature.py │ ├── fee.py │ ├── gateway_balances.py │ ├── generic_request.py │ ├── get_aggregate_price.py │ ├── ledger.py │ ├── ledger_closed.py │ ├── ledger_current.py │ ├── ledger_data.py │ ├── ledger_entry.py │ ├── manifest.py │ ├── nft_buy_offers.py │ ├── nft_history.py │ ├── nft_info.py │ ├── nft_sell_offers.py │ ├── nfts_by_issuer.py │ ├── no_ripple_check.py │ ├── path_find.py │ ├── ping.py │ ├── py.typed │ ├── random.py │ ├── request.py │ ├── ripple_path_find.py │ ├── server_definitions.py │ ├── server_info.py │ ├── server_state.py │ ├── sign.py │ ├── sign_and_submit.py │ ├── sign_for.py │ ├── simulate.py │ ├── submit.py │ ├── submit_multisigned.py │ ├── submit_only.py │ ├── subscribe.py │ ├── transaction_entry.py │ ├── tx.py │ └── unsubscribe.py ├── required.py ├── response.py ├── transactions │ ├── __init__.py │ ├── account_delete.py │ ├── account_set.py │ ├── amm_bid.py │ ├── amm_clawback.py │ ├── amm_create.py │ ├── amm_delete.py │ ├── amm_deposit.py │ ├── amm_vote.py │ ├── amm_withdraw.py │ ├── batch.py │ ├── check_cancel.py │ ├── check_cash.py │ ├── check_create.py │ ├── clawback.py │ ├── credential_accept.py │ ├── credential_create.py │ ├── credential_delete.py │ ├── delegate_set.py │ ├── deposit_preauth.py │ ├── did_delete.py │ ├── did_set.py │ ├── escrow_cancel.py │ ├── escrow_create.py │ ├── escrow_finish.py │ ├── metadata.py │ ├── mptoken_authorize.py │ ├── mptoken_issuance_create.py │ ├── mptoken_issuance_destroy.py │ ├── mptoken_issuance_set.py │ ├── nftoken_accept_offer.py │ ├── nftoken_burn.py │ ├── nftoken_cancel_offer.py │ ├── nftoken_create_offer.py │ ├── nftoken_mint.py │ ├── nftoken_modify.py │ ├── offer_cancel.py │ ├── offer_create.py │ ├── oracle_delete.py │ ├── oracle_set.py │ ├── payment.py │ ├── payment_channel_claim.py │ ├── payment_channel_create.py │ ├── payment_channel_fund.py │ ├── permissioned_domain_delete.py │ ├── permissioned_domain_set.py │ ├── pseudo_transactions │ │ ├── __init__.py │ │ ├── enable_amendment.py │ │ ├── pseudo_transaction.py │ │ ├── set_fee.py │ │ └── unl_modify.py │ ├── py.typed │ ├── set_regular_key.py │ ├── signer_list_set.py │ ├── ticket_create.py │ ├── transaction.py │ ├── trust_set.py │ ├── types │ │ ├── __init__.py │ │ ├── pseudo_transaction_type.py │ │ └── transaction_type.py │ ├── xchain_account_create_commit.py │ ├── xchain_add_account_create_attestation.py │ ├── xchain_add_claim_attestation.py │ ├── xchain_claim.py │ ├── xchain_commit.py │ ├── xchain_create_bridge.py │ ├── xchain_create_claim_id.py │ └── xchain_modify_bridge.py ├── types.py ├── utils.py └── xchain_bridge.py ├── py.typed ├── transaction ├── __init__.py ├── batch_signers.py ├── main.py ├── multisign.py ├── py.typed └── reliable_submission.py ├── utils ├── __init__.py ├── get_nftoken_id.py ├── get_xchain_claim_id.py ├── parse_nftoken_id.py ├── py.typed ├── str_conversions.py ├── time_conversions.py ├── txn_parser │ ├── __init__.py │ ├── get_balance_changes.py │ ├── get_final_balances.py │ ├── get_order_book_changes.py │ └── utils │ │ ├── __init__.py │ │ ├── balance_parser.py │ │ ├── nodes.py │ │ ├── order_book_parser.py │ │ ├── parser.py │ │ └── types.py └── xrp_conversions.py └── wallet ├── __init__.py ├── main.py ├── py.typed └── wallet_generation.py /.coderabbit.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json 2 | language: "en-US" 3 | reviews: 4 | # Set the profile for reviews. Assertive profile yields more feedback, that may be considered nitpicky. 5 | profile: "chill" 6 | # Approve the review once CodeRabbit's comments are resolved. Note: In GitLab, all discussions must be resolved. 7 | request_changes_workflow: false 8 | # Generate a high level summary of the changes in the PR/MR description. 9 | high_level_summary: false 10 | # Generate a poem in the walkthrough comment. 11 | poem: true 12 | # Post review details on each review. Additionally, post a review status when a review is skipped in certain cases. 13 | review_status: true 14 | # Generate walkthrough in a markdown collapsible section. 15 | collapse_walkthrough: false 16 | # Abort the in-progress review if the pull request is closed or merged. 17 | abort_on_close: true 18 | auto_review: 19 | # Automatic Review | Automatic code review 20 | enabled: true 21 | # Review draft PRs/MRs. 22 | drafts: false 23 | # Ignore reviewing if the title of the pull request contains any of these keywords (case-insensitive). 24 | ignore_title_keywords: 25 | - build( 26 | chat: 27 | # Enable the bot to reply automatically without requiring the user to tag it. 28 | auto_reply: true 29 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | # As defined at https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings 3 | docstring-convention=google 4 | 5 | # D212 and D213 are mutually exclusive, so we're only allowing D213. 6 | # D205 and D415 don't like multi-line summary statements, which is annoying. 7 | # E203 and W503 don't interact well with black 8 | ignore = D205,D212,D415,E203,W503 9 | 10 | # This is the line length that black uses 11 | # https://black.readthedocs.io/en/stable/the_black_code_style.html#line-length 12 | max-line-length = 88 13 | 14 | # This is for pydocstyle - to allow docstrings in __init__ functions 15 | # This rule was used for easier migration from darglint 16 | # TODO: remove this rule 17 | allow-init-docstring=True 18 | 19 | per-file-ignores = 20 | # For tests, disable type annotation and docstring linting. 21 | tests/*: ANN D DOC 22 | 23 | # Select other tools to enable. 24 | 25 | # ABS enables absolute import checks. 26 | 27 | # ANN enables linting for type annotations. 28 | 29 | # BLK enables using black --check from within flake8. 30 | 31 | # D enables docstrings warnings from pydocstyle. 32 | 33 | # DOC enables docstring style linting via pydoclint. 34 | 35 | # F are errors reported by pyflakes, a tool which parses source files 36 | # and finds invalid Python code. 37 | 38 | # I is linting errors related to isort, which is the source of truth 39 | # for how imports should be ordered. 40 | 41 | # W and E are warnings and errors reported by pycodestyle, which checks 42 | # your Python code against some of the style conventions in PEP 8. 43 | select = ABS,ANN,DOC,BLK,D,E,F,I,W 44 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: pip 4 | directory: "/" 5 | schedule: 6 | interval: monthly 7 | time: "15:00" 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## High Level Overview of Change 2 | 3 | 8 | 9 | ### Context of Change 10 | 11 | 19 | 20 | ### Type of Change 21 | 22 | 25 | 26 | - [ ] Bug fix (non-breaking change which fixes an issue) 27 | - [ ] New feature (non-breaking change which adds functionality) 28 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 29 | - [ ] Refactor (non-breaking change that only restructures code) 30 | - [ ] Tests (You added tests for code that already exists, or your new feature included in this PR) 31 | - [ ] Documentation Updates 32 | - [ ] Release 33 | 34 | ### Did you update CHANGELOG.md? 35 | 36 | - [ ] Yes 37 | - [ ] No, this change does not impact library users 38 | 39 | ## Test Plan 40 | 41 | 44 | 45 | 49 | -------------------------------------------------------------------------------- /.github/workflows/faucet_test.yml: -------------------------------------------------------------------------------- 1 | name: Faucet tests 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | workflow_dispatch: 7 | 8 | env: 9 | POETRY_VERSION: 2.1.1 10 | 11 | jobs: 12 | faucet-test: 13 | name: Faucet test 14 | runs-on: ubuntu-latest 15 | strategy: 16 | max-parallel: 1 17 | matrix: 18 | python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] 19 | 20 | steps: 21 | - name: Checkout code 22 | uses: actions/checkout@v4 23 | 24 | - name: Load cached .local 25 | id: cache-poetry 26 | uses: actions/cache@v4 27 | with: 28 | path: /home/runner/.local 29 | key: dotlocal-${{ env.POETRY_VERSION }} 30 | 31 | - name: Install poetry 32 | if: steps.cache-poetry.outputs.cache-hit != 'true' 33 | run: | 34 | curl -sSL https://install.python-poetry.org/ | python - --version ${{ env.POETRY_VERSION }} 35 | echo "$HOME/.local/bin" >> $GITHUB_PATH 36 | 37 | - name: Install Python + Retrieve Poetry dependencies from cache 38 | uses: actions/setup-python@v5 39 | with: 40 | python-version: ${{ matrix.python-version }} 41 | cache: "poetry" 42 | 43 | - name: Display Python version 44 | run: | 45 | python -c "import sys; print(sys.version)" 46 | 47 | - name: Install poetry dependencies 48 | run: poetry install 49 | 50 | - name: Run Faucet tests 51 | run: poetry run poe test_faucet 52 | 53 | -------------------------------------------------------------------------------- /.github/workflows/snippet_test.yml: -------------------------------------------------------------------------------- 1 | name: Snippets 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | workflow_dispatch: 7 | 8 | env: 9 | POETRY_VERSION: 2.1.1 10 | 11 | jobs: 12 | snippet-test: 13 | name: Snippet test 14 | runs-on: ubuntu-latest 15 | strategy: 16 | max-parallel: 1 17 | matrix: 18 | python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] 19 | 20 | steps: 21 | - name: Checkout code 22 | uses: actions/checkout@v4 23 | 24 | - name: Load cached .local 25 | id: cache-poetry 26 | uses: actions/cache@v4 27 | with: 28 | path: /home/runner/.local 29 | key: dotlocal-${{ env.POETRY_VERSION }} 30 | 31 | - name: Install poetry 32 | if: steps.cache-poetry.outputs.cache-hit != 'true' 33 | run: | 34 | curl -sSL https://install.python-poetry.org/ | python - --version ${{ env.POETRY_VERSION }} 35 | echo "$HOME/.local/bin" >> $GITHUB_PATH 36 | 37 | - name: Install Python + Retrieve Poetry dependencies from cache 38 | uses: actions/setup-python@v5 39 | with: 40 | python-version: ${{ matrix.python-version }} 41 | cache: "poetry" 42 | 43 | - name: Display Python version 44 | run: | 45 | python -c "import sys; print(sys.version)" 46 | 47 | - name: Install poetry dependencies 48 | run: poetry install 49 | 50 | - name: Run Snippets 51 | run: (for i in snippets/*.py; do echo "Running $i" && poetry run python $i && sleep 15 || exit 1; done) 52 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # .pre-commit-config.yaml 2 | repos: 3 | - repo: https://github.com/pre-commit/pre-commit-hooks 4 | rev: v2.3.0 5 | hooks: 6 | - id: check-yaml 7 | - id: end-of-file-fixer 8 | - id: trailing-whitespace 9 | # Use our local versions of tools so that we stay in sync. 10 | - repo: local 11 | hooks: 12 | - id: isort 13 | name: isort 14 | entry: poetry run isort 15 | language: system 16 | types: [python] 17 | - id: black 18 | name: black 19 | entry: poetry run black 20 | language: system 21 | types: [python] 22 | - id: flake8 23 | name: flake8 24 | entry: poetry run flake8 25 | language: system 26 | types: [python] 27 | - id: mypy 28 | name: mypy 29 | entry: poetry run mypy 30 | args: ["--strict", "--implicit-reexport"] 31 | language: system 32 | files: xrpl/ 33 | types: [python] 34 | - id: sphinx 35 | name: sphinx 36 | entry: poetry run sphinx-apidoc -o docs/source xrpl 37 | language: system 38 | pass_filenames: false 39 | files: __init__ 40 | exclude: ^tests 41 | types: [python] 42 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file for Sphinx projects 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | version: 2 4 | 5 | # Set the version of Python and other tools you might need 6 | build: 7 | os: ubuntu-22.04 8 | tools: 9 | python: "3.11" 10 | jobs: 11 | post_create_environment: 12 | # Install poetry 13 | # https://python-poetry.org/docs/#installing-manually 14 | - python -m pip install poetry 15 | post_install: 16 | # Install dependencies with 'docs' dependency group 17 | # https://python-poetry.org/docs/managing-dependencies/#dependency-groups 18 | - VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH poetry install 19 | 20 | python: 21 | install: 22 | - method: pip 23 | path: . 24 | 25 | sphinx: 26 | builder: html 27 | configuration: docs/conf.py 28 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-python.flake8", 4 | "ms-python.black-formatter", 5 | "ms-python.mypy-type-checker", 6 | "swyddfa.esbonio", 7 | "streetsidesoftware.code-spell-checker", 8 | "njqdev.vscode-python-typehint", 9 | "ms-python.isort", 10 | "ms-python.pylint" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "addresscodec", 4 | "aiounittest", 5 | "altnet", 6 | "asyncio", 7 | "autofilling", 8 | "autofills", 9 | "binarycodec", 10 | "Clawback", 11 | "isnumeric", 12 | "keypair", 13 | "keypairs", 14 | "multiaccount", 15 | "multisign", 16 | "multisigned", 17 | "multisigning", 18 | "nftoken", 19 | "PATHSET", 20 | "rippletest", 21 | "ripplex", 22 | "sfield", 23 | "sfields", 24 | "xaddress", 25 | "xchain" 26 | ], 27 | "[python]": { 28 | "editor.defaultFormatter": "ms-python.black-formatter", 29 | "editor.formatOnSave": true, 30 | "editor.codeActionsOnSave": { 31 | "source.organizeImports": "always" 32 | } 33 | }, 34 | "isort.args": [ 35 | "--profile", 36 | "black" 37 | ], 38 | "python.testing.pytestEnabled": false, 39 | "python.testing.unittestEnabled": true 40 | } 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021, XRP Ledger Foundation 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. 4 | 5 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 6 | INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE 7 | FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 8 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 9 | OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 10 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include binary_codec/definitions/definitions.json 2 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/source/modules.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | -------------------------------------------------------------------------------- /docs/source/snippets.rst: -------------------------------------------------------------------------------- 1 | XRPL Code Snippets 2 | =================== 3 | 4 | Code snippets to demonstrate basic usage of the xrpl-py library. 5 | 6 | .. toctree:: 7 | :maxdepth: 1 8 | 9 | Look Up a Transaction on the Ledger 10 | ------------------------------------- 11 | 12 | .. literalinclude:: ../../snippets/get_transaction.py 13 | 14 | Send a Transaction and See if It Gets Validated 15 | ----------------------------------------------- 16 | 17 | .. literalinclude:: ../../snippets/submit_payment.py 18 | 19 | Set a Regular Key 20 | ----------------------------------------------- 21 | 22 | .. literalinclude:: ../../snippets/set_regular_key.py 23 | 24 | Set up an Escrow 25 | ----------------- 26 | 27 | .. literalinclude:: ../../snippets/send_escrow.py 28 | 29 | Find the Best Path to Trade With 30 | ---------------------------------- 31 | 32 | .. literalinclude:: ../../snippets/paths.py 33 | 34 | Handle Partial Payments 35 | ------------------------ 36 | 37 | .. literalinclude:: ../../snippets/partial_payment.py 38 | -------------------------------------------------------------------------------- /docs/source/xrpl.account.rst: -------------------------------------------------------------------------------- 1 | Account Methods 2 | ==================== 3 | 4 | .. automodule:: xrpl.account 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/xrpl.asyncio.account.rst: -------------------------------------------------------------------------------- 1 | Account Methods 2 | ==================== 3 | 4 | .. automodule:: xrpl.asyncio.account 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/xrpl.asyncio.clients.rst: -------------------------------------------------------------------------------- 1 | Async Network Clients 2 | ======================= 3 | 4 | .. automodule:: xrpl.asyncio.clients 5 | :members: 6 | :inherited-members: 7 | -------------------------------------------------------------------------------- /docs/source/xrpl.asyncio.ledger.rst: -------------------------------------------------------------------------------- 1 | Ledger Methods 2 | =================== 3 | 4 | .. automodule:: xrpl.asyncio.ledger 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/xrpl.asyncio.rst: -------------------------------------------------------------------------------- 1 | Async Support 2 | =================== 3 | 4 | The `xrpl-py` library supports `Python's asyncio implementation `_. All of these methods are equivalent to the synchronous ones. 5 | 6 | Due to the way that `asyncio` event loops are handled, you cannot call synchronous methods from asynchronous code. Each synchronous method has an equivalent asynchronous method in this module that should be used instead. 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | :titlesonly: 11 | 12 | xrpl.asyncio.account 13 | xrpl.asyncio.ledger 14 | xrpl.asyncio.transaction 15 | xrpl.asyncio.wallet 16 | xrpl.asyncio.clients 17 | -------------------------------------------------------------------------------- /docs/source/xrpl.asyncio.transaction.rst: -------------------------------------------------------------------------------- 1 | Transaction Methods 2 | ======================== 3 | 4 | .. automodule:: xrpl.asyncio.transaction 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/xrpl.asyncio.wallet.rst: -------------------------------------------------------------------------------- 1 | Wallet Methods 2 | =================== 3 | 4 | .. automodule:: xrpl.asyncio.wallet 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/xrpl.clients.rst: -------------------------------------------------------------------------------- 1 | Network Clients 2 | ==================== 3 | 4 | .. automodule:: xrpl.clients 5 | :members: 6 | :inherited-members: 7 | -------------------------------------------------------------------------------- /docs/source/xrpl.core.addresscodec.rst: -------------------------------------------------------------------------------- 1 | XRPL Address Codec 2 | ================== 3 | 4 | .. automodule:: xrpl.core.addresscodec 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/xrpl.core.binarycodec.binary_wrappers.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | -------------------------------------------------------------------------------- /docs/source/xrpl.core.binarycodec.definitions.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | -------------------------------------------------------------------------------- /docs/source/xrpl.core.binarycodec.rst: -------------------------------------------------------------------------------- 1 | XRPL Binary Codec 2 | ================= 3 | 4 | .. automodule:: xrpl.core.binarycodec 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/xrpl.core.binarycodec.types.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | -------------------------------------------------------------------------------- /docs/source/xrpl.core.keypairs.rst: -------------------------------------------------------------------------------- 1 | XRPL Keypairs Codec 2 | =================== 3 | 4 | .. automodule:: xrpl.core.keypairs 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/xrpl.core.rst: -------------------------------------------------------------------------------- 1 | XRPL Core Codecs 2 | ================ 3 | 4 | The address codec, binary codec, and keypairs codec all contain the underlying functionality 5 | necessary to work with the XRPL, such as signing and serialization and key generation. 6 | 7 | .. toctree:: 8 | :maxdepth: 1 9 | 10 | xrpl.core.addresscodec 11 | xrpl.core.binarycodec 12 | xrpl.core.keypairs 13 | -------------------------------------------------------------------------------- /docs/source/xrpl.ledger.rst: -------------------------------------------------------------------------------- 1 | Ledger Methods 2 | =================== 3 | 4 | .. automodule:: xrpl.ledger 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/xrpl.models.amounts.rst: -------------------------------------------------------------------------------- 1 | XRPL Amount Models 2 | ================== 3 | 4 | .. automodule:: xrpl.models.amounts 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | :inherited-members: 9 | 10 | .. autodata:: Amount 11 | -------------------------------------------------------------------------------- /docs/source/xrpl.models.currencies.rst: -------------------------------------------------------------------------------- 1 | XRPL Currency Models 2 | ==================== 3 | 4 | .. automodule:: xrpl.models.currencies 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | :inherited-members: 9 | 10 | .. autodata:: Currency 11 | -------------------------------------------------------------------------------- /docs/source/xrpl.models.requests.rst: -------------------------------------------------------------------------------- 1 | XRPL Request Models 2 | =================== 3 | 4 | Base Request Model 5 | ------------------ 6 | 7 | .. autoclass:: xrpl.models.requests.request.Request 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | :inherited-members: 12 | 13 | Specific Request Types 14 | ---------------------- 15 | 16 | .. automodule:: xrpl.models.requests 17 | :members: 18 | :undoc-members: 19 | :show-inheritance: 20 | :inherited-members: 21 | -------------------------------------------------------------------------------- /docs/source/xrpl.models.rst: -------------------------------------------------------------------------------- 1 | XRPL Models 2 | =========== 3 | 4 | Use these classes to validate the formats for all types of data coming from or 5 | going to the XRP Ledger. 6 | 7 | .. toctree:: 8 | :maxdepth: 1 9 | :titlesonly: 10 | 11 | xrpl.models.amounts 12 | xrpl.models.currencies 13 | xrpl.models.requests 14 | xrpl.models.transactions 15 | xrpl.models.transactions.pseudo_transactions 16 | 17 | Base Model 18 | ---------- 19 | 20 | .. automodule:: xrpl.models.base_model 21 | :members: 22 | :undoc-members: 23 | :show-inheritance: 24 | 25 | Response Model 26 | -------------- 27 | 28 | .. automodule:: xrpl.models.response 29 | :members: 30 | :undoc-members: 31 | :show-inheritance: 32 | 33 | Exceptions 34 | ---------- 35 | 36 | .. automodule:: xrpl.models.exceptions 37 | :members: 38 | :undoc-members: 39 | :show-inheritance: 40 | -------------------------------------------------------------------------------- /docs/source/xrpl.models.transactions.pseudo_transactions.rst: -------------------------------------------------------------------------------- 1 | XRPL Pseudo-Transaction Models 2 | ============================== 3 | 4 | .. automodule:: xrpl.models.transactions.pseudo_transactions 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | :inherited-members: 9 | -------------------------------------------------------------------------------- /docs/source/xrpl.models.transactions.rst: -------------------------------------------------------------------------------- 1 | XRPL Transaction Models 2 | ======================= 3 | 4 | Use these models to prepare or process XRP Ledger transactions. 5 | 6 | Base Transaction Model 7 | ---------------------- 8 | 9 | .. autoclass:: xrpl.models.transactions.transaction.Transaction 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | :inherited-members: 14 | 15 | Specific Transaction Types 16 | -------------------------- 17 | 18 | .. automodule:: xrpl.models.transactions 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | :inherited-members: 23 | -------------------------------------------------------------------------------- /docs/source/xrpl.models.transactions.types.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | -------------------------------------------------------------------------------- /docs/source/xrpl.rst: -------------------------------------------------------------------------------- 1 | XRPL Global Variables 2 | ===================== 3 | 4 | .. automodule:: xrpl.constants 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/xrpl.transaction.rst: -------------------------------------------------------------------------------- 1 | Transaction Methods 2 | ======================== 3 | 4 | .. automodule:: xrpl.transaction 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/xrpl.utils.rst: -------------------------------------------------------------------------------- 1 | Utilities 2 | ============== 3 | 4 | .. automodule:: xrpl.utils 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/xrpl.utils.txn_parser.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | -------------------------------------------------------------------------------- /docs/source/xrpl.utils.txn_parser.utils.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | -------------------------------------------------------------------------------- /docs/source/xrpl.wallet.rst: -------------------------------------------------------------------------------- 1 | Wallet Methods 2 | =================== 3 | 4 | .. automodule:: xrpl.wallet 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | exclude = dist 3 | -------------------------------------------------------------------------------- /poetry.toml: -------------------------------------------------------------------------------- 1 | # This makes it so that the virtual env is created in a .venv 2 | # folder in this repo instead of globally, which has better 3 | # support for environments like VSCode and PyCharm. 4 | 5 | [virtualenvs] 6 | create = true 7 | in-project = true 8 | -------------------------------------------------------------------------------- /py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/py.typed -------------------------------------------------------------------------------- /snippets/README.md: -------------------------------------------------------------------------------- 1 | # More XRPL Code Samples 2 | 3 | - For samples of common use cases, see the [XRPL.org Code Samples](https://xrpl.org/code-samples.html) page. 4 | - You can also browse those samples [directly on GitHub](https://github.com/XRPLF/xrpl-dev-portal/tree/master/content/_code-samples). 5 | -------------------------------------------------------------------------------- /snippets/get_transaction.py: -------------------------------------------------------------------------------- 1 | """Example of how we can see a transaction that was validated on the ledger""" 2 | 3 | from xrpl.clients import JsonRpcClient 4 | from xrpl.models import Ledger, Tx 5 | 6 | # References 7 | # - https://xrpl.org/look-up-transaction-results.html 8 | # - https://xrpl.org/parallel-networks.html#parallel-networks 9 | # - https://xrpl.org/tx.html 10 | 11 | # Create a client to connect to the main network 12 | client = JsonRpcClient("https://xrplcluster.com/") 13 | 14 | # Create a Ledger request and have the client call it 15 | ledger_request = Ledger(ledger_index="validated", transactions=True) 16 | ledger_response = client.request(ledger_request) 17 | print(ledger_response) 18 | 19 | # Extract out transactions from the ledger response 20 | transactions = ledger_response.result["ledger"]["transactions"] 21 | 22 | # If there are transactions, we can display the first one 23 | # If there are none (visualized at https://testnet.xrpl.org/), try re running the script 24 | if transactions: 25 | # Create a Transaction request and have the client call it 26 | tx_request = Tx(transaction=transactions[0]) 27 | tx_response = client.request(tx_request) 28 | print(tx_response) 29 | else: 30 | print("No transactions were found on the ledger!") 31 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/__init__.py -------------------------------------------------------------------------------- /tests/integration/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/integration/__init__.py -------------------------------------------------------------------------------- /tests/integration/clients/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/integration/clients/__init__.py -------------------------------------------------------------------------------- /tests/integration/clients/test_json_rpc_client.py: -------------------------------------------------------------------------------- 1 | """Test the json_rpc_client.""" 2 | 3 | from __future__ import annotations 4 | 5 | from unittest import TestCase 6 | 7 | from xrpl.clients import JsonRpcClient 8 | from xrpl.models.requests import ServerInfo 9 | 10 | 11 | class TestJsonRpcClient(TestCase): 12 | """Test json_rpc_client.""" 13 | 14 | def test_json_rpc_client_valid_url(self) -> None: 15 | # Valid URL 16 | JSON_RPC_URL = "https://s.altnet.rippletest.net:51234" 17 | client = JsonRpcClient(JSON_RPC_URL) 18 | client.request(ServerInfo()) 19 | -------------------------------------------------------------------------------- /tests/integration/integration_test_case.py: -------------------------------------------------------------------------------- 1 | try: 2 | from unittest import IsolatedAsyncioTestCase 3 | except ImportError: 4 | from aiounittest import AsyncTestCase as IsolatedAsyncioTestCase # type: ignore 5 | 6 | from tests.integration.it_utils import WEBSOCKET_CLIENT, WEBSOCKET_TESTNET_CLIENT 7 | 8 | 9 | class IntegrationTestCase(IsolatedAsyncioTestCase): 10 | @classmethod 11 | def setUpClass(cls): 12 | WEBSOCKET_CLIENT.open() 13 | WEBSOCKET_TESTNET_CLIENT.open() 14 | 15 | @classmethod 16 | def tearDownClass(cls): 17 | WEBSOCKET_CLIENT.close() 18 | WEBSOCKET_TESTNET_CLIENT.close() 19 | -------------------------------------------------------------------------------- /tests/integration/reqs/__init__.py: -------------------------------------------------------------------------------- 1 | # We named this module `reqs` instead of `requests` to get around a name 2 | # collision with the `requests` library when running integration tests. Seems 3 | # to be an issue with `unittest discover` and the fact that each directory 4 | # needs to be its own module, meaning that if this were called `requests` 5 | # then it does actually conflict with the library.... 6 | -------------------------------------------------------------------------------- /tests/integration/reqs/test_account_info.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import test_async_and_sync 3 | from tests.integration.reusable_values import WALLET 4 | from xrpl.models.requests import AccountInfo 5 | 6 | 7 | class TestAccountInfo(IntegrationTestCase): 8 | @test_async_and_sync(globals()) 9 | async def test_basic_functionality(self, client): 10 | response = await client.request( 11 | AccountInfo( 12 | account=WALLET.address, 13 | ) 14 | ) 15 | self.assertTrue(response.is_successful()) 16 | -------------------------------------------------------------------------------- /tests/integration/reqs/test_account_objects.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import test_async_and_sync 3 | from tests.integration.reusable_values import WALLET 4 | from xrpl.models.requests import AccountObjects 5 | 6 | 7 | class TestAccountObjects(IntegrationTestCase): 8 | @test_async_and_sync(globals()) 9 | async def test_basic_functionality(self, client): 10 | response = await client.request( 11 | AccountObjects( 12 | account=WALLET.address, 13 | ) 14 | ) 15 | self.assertTrue(response.is_successful()) 16 | -------------------------------------------------------------------------------- /tests/integration/reqs/test_amm_info.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import test_async_and_sync 3 | from tests.integration.reusable_values import AMM_ASSET, AMM_ASSET2 4 | from xrpl.models.requests.amm_info import AMMInfo 5 | 6 | asset = AMM_ASSET 7 | asset2 = AMM_ASSET2 8 | 9 | 10 | class TestAMMInfo(IntegrationTestCase): 11 | @test_async_and_sync(globals()) 12 | async def test_basic_functionality(self, client): 13 | amm_info = await client.request( 14 | AMMInfo( 15 | asset=asset, 16 | asset2=asset2, 17 | ) 18 | ) 19 | 20 | self.assertEqual(float(amm_info.result["amm"]["amount"]), 1250) 21 | self.assertEqual( 22 | amm_info.result["amm"]["amount2"], 23 | { 24 | "currency": asset2.currency, 25 | "issuer": asset2.issuer, 26 | "value": "250", 27 | }, 28 | ) 29 | -------------------------------------------------------------------------------- /tests/integration/reqs/test_book_offers.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import test_async_and_sync 3 | from tests.integration.reusable_values import WALLET 4 | from xrpl.models.currencies import XRP, IssuedCurrency 5 | from xrpl.models.requests import BookOffers 6 | 7 | 8 | class TestBookOffers(IntegrationTestCase): 9 | @test_async_and_sync(globals()) 10 | async def test_basic_functionality(self, client): 11 | response = await client.request( 12 | BookOffers( 13 | taker=WALLET.address, 14 | taker_gets=XRP(), 15 | taker_pays=IssuedCurrency( 16 | currency="USD", 17 | issuer="rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B", 18 | ), 19 | ledger_index="validated", 20 | ), 21 | ) 22 | self.assertTrue(response.is_successful()) 23 | -------------------------------------------------------------------------------- /tests/integration/reqs/test_channel_verify.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import test_async_and_sync 3 | from tests.integration.reusable_values import PAYMENT_CHANNEL, WALLET 4 | from xrpl.models.requests import ChannelVerify 5 | 6 | 7 | class TestChannelVerify(IntegrationTestCase): 8 | @test_async_and_sync(globals()) 9 | async def test_basic_functionality(self, client): 10 | response = await client.request( 11 | ChannelVerify( 12 | channel_id=PAYMENT_CHANNEL.result["tx_json"]["hash"], 13 | amount="1", 14 | public_key=WALLET.public_key, 15 | signature="304402204EF0AFB78AC23ED1C472E74F4299C0C21", 16 | ), 17 | ) 18 | self.assertTrue(response.is_successful()) 19 | -------------------------------------------------------------------------------- /tests/integration/reqs/test_feature.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import test_async_and_sync 3 | from xrpl.models.requests import Feature 4 | 5 | AMM_AMENDMENT = "8CC0774A3BF66D1D22E76BBDA8E8A232E6B6313834301B3B23E8601196AE6455" 6 | 7 | 8 | class TestFeature(IntegrationTestCase): 9 | @test_async_and_sync(globals()) 10 | async def test_basic_functionality(self, client): 11 | response = await client.request(Feature()) 12 | features = response.result["features"] 13 | 14 | self.assertIn(AMM_AMENDMENT, features) 15 | feature_info = features[AMM_AMENDMENT] 16 | self.assertEqual(feature_info["name"], "AMM") 17 | self.assertTrue(isinstance(feature_info["enabled"], bool)) 18 | self.assertEqual(feature_info["supported"], True) 19 | 20 | @test_async_and_sync(globals()) 21 | async def test_single_feature(self, client): 22 | response = await client.request(Feature(feature=AMM_AMENDMENT)) 23 | features = response.result 24 | 25 | self.assertIn(AMM_AMENDMENT, features) 26 | feature_info = features[AMM_AMENDMENT] 27 | self.assertEqual(feature_info["name"], "AMM") 28 | self.assertTrue(isinstance(feature_info["enabled"], bool)) 29 | self.assertEqual(feature_info["supported"], True) 30 | -------------------------------------------------------------------------------- /tests/integration/reqs/test_ledger.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import test_async_and_sync 3 | from xrpl.models.requests import Ledger 4 | 5 | 6 | class TestLedger(IntegrationTestCase): 7 | @test_async_and_sync(globals()) 8 | async def test_basic_functionality(self, client): 9 | response = await client.request(Ledger()) 10 | self.assertTrue(response.is_successful()) 11 | -------------------------------------------------------------------------------- /tests/integration/reqs/test_no_ripple_check.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import test_async_and_sync 3 | from tests.integration.reusable_values import WALLET 4 | from xrpl.models.requests import NoRippleCheck, NoRippleCheckRole 5 | 6 | 7 | class TestNoRippleCheck(IntegrationTestCase): 8 | @test_async_and_sync(globals()) 9 | async def test_basic_functionality(self, client): 10 | response = await client.request( 11 | NoRippleCheck( 12 | account=WALLET.address, 13 | role=NoRippleCheckRole.USER, 14 | ) 15 | ) 16 | self.assertTrue(response.is_successful()) 17 | -------------------------------------------------------------------------------- /tests/integration/reqs/test_ripple_path_find.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import test_async_and_sync 3 | from tests.integration.reusable_values import DESTINATION, WALLET 4 | from xrpl.models.requests import RipplePathFind 5 | 6 | 7 | class TestRipplePathFind(IntegrationTestCase): 8 | @test_async_and_sync(globals()) 9 | async def test_basic_functionality(self, client): 10 | response = await client.request( 11 | RipplePathFind( 12 | source_account=WALLET.address, 13 | destination_account=DESTINATION.address, 14 | destination_amount="100", 15 | ), 16 | ) 17 | self.assertTrue(response.is_successful()) 18 | -------------------------------------------------------------------------------- /tests/integration/reqs/test_server_definitions.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import test_async_and_sync 3 | from xrpl.models.requests import ServerDefinitions 4 | 5 | 6 | class TestServerDefinitions(IntegrationTestCase): 7 | @test_async_and_sync(globals()) 8 | async def test_basic_functionality(self, client): 9 | response = await client.request(ServerDefinitions()) 10 | self.assertTrue(response.is_successful()) 11 | -------------------------------------------------------------------------------- /tests/integration/reqs/test_server_info.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import test_async_and_sync 3 | from xrpl.models.requests import ServerInfo 4 | 5 | 6 | class TestServerInfo(IntegrationTestCase): 7 | @test_async_and_sync(globals()) 8 | async def test_basic_functionality(self, client): 9 | response = await client.request(ServerInfo()) 10 | self.assertTrue(response.is_successful()) 11 | -------------------------------------------------------------------------------- /tests/integration/reqs/test_simulate.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import test_async_and_sync 3 | from tests.integration.reusable_values import WALLET 4 | from xrpl.models import AccountSet, Simulate 5 | 6 | 7 | class TestSimulate(IntegrationTestCase): 8 | @test_async_and_sync(globals()) 9 | async def test_basic_functionality(self, client): 10 | response = await client.request( 11 | Simulate(transaction=AccountSet(account=WALLET.classic_address)) 12 | ) 13 | 14 | self.assertEqual(response.type, "response") 15 | self.assertIn( 16 | "meta", response.result, "Key 'meta' not found in simulate response." 17 | ) 18 | self.assertIsInstance( 19 | response.result["meta"], dict, "'meta' should be a dictionary." 20 | ) 21 | self.assertEqual(response.result["engine_result"], "tesSUCCESS") 22 | self.assertEqual(response.result["engine_result_code"], 0) 23 | self.assertFalse(response.result["applied"]) 24 | -------------------------------------------------------------------------------- /tests/integration/reqs/test_submit_only.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import test_async_and_sync 3 | from tests.integration.reusable_values import WALLET 4 | from xrpl.asyncio.transaction import autofill_and_sign 5 | from xrpl.core.binarycodec import encode 6 | from xrpl.models.amounts import IssuedCurrencyAmount 7 | from xrpl.models.requests import SubmitOnly 8 | from xrpl.models.transactions import OfferCreate 9 | 10 | TX = OfferCreate( 11 | account=WALLET.address, 12 | taker_gets="13100000", 13 | taker_pays=IssuedCurrencyAmount( 14 | currency="USD", 15 | issuer=WALLET.address, 16 | value="10", 17 | ), 18 | ) 19 | 20 | 21 | class TestSubmitOnly(IntegrationTestCase): 22 | @test_async_and_sync(globals(), ["xrpl.transaction.autofill_and_sign"]) 23 | async def test_basic_functionality(self, client): 24 | transaction = await autofill_and_sign(TX, client, WALLET) 25 | 26 | tx_json = transaction.to_xrpl() 27 | tx_blob = encode(tx_json) 28 | response = await client.request( 29 | SubmitOnly( 30 | tx_blob=tx_blob, 31 | ) 32 | ) 33 | self.assertTrue(response.is_successful()) 34 | -------------------------------------------------------------------------------- /tests/integration/reqs/test_tx.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import test_async_and_sync 3 | from tests.integration.reusable_values import OFFER 4 | from xrpl.models.requests import Tx 5 | 6 | 7 | class TestTx(IntegrationTestCase): 8 | @test_async_and_sync(globals()) 9 | async def test_basic_functionality(self, client): 10 | response = await client.request( 11 | Tx( 12 | transaction=OFFER.result["tx_json"]["hash"], 13 | ), 14 | ) 15 | self.assertTrue(response.is_successful()) 16 | -------------------------------------------------------------------------------- /tests/integration/sugar/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/integration/sugar/__init__.py -------------------------------------------------------------------------------- /tests/integration/sugar/test_ledger.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import test_async_and_sync 3 | from xrpl.asyncio.ledger import get_fee, get_latest_open_ledger_sequence 4 | from xrpl.utils import drops_to_xrp 5 | 6 | 7 | class TestLedger(IntegrationTestCase): 8 | @test_async_and_sync(globals(), ["xrpl.ledger.get_fee"]) 9 | async def test_get_fee_max(self, client): 10 | expected = "1" 11 | max_fee = drops_to_xrp(expected) 12 | result = await get_fee(client, max_fee=max_fee) 13 | self.assertEqual(result, expected) 14 | 15 | @test_async_and_sync( 16 | globals(), 17 | ["xrpl.ledger.get_latest_open_ledger_sequence"], 18 | use_testnet=True, 19 | ) 20 | async def test_fetch_current_ledger(self, client): 21 | response = await get_latest_open_ledger_sequence(client) 22 | self.assertTrue(isinstance(response, int)) 23 | -------------------------------------------------------------------------------- /tests/integration/transactions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/integration/transactions/__init__.py -------------------------------------------------------------------------------- /tests/integration/transactions/test_amm_create.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import create_amm_pool_async, test_async_and_sync 3 | from xrpl.models.requests.amm_info import AMMInfo 4 | 5 | 6 | class TestAMMCreate(IntegrationTestCase): 7 | @test_async_and_sync(globals()) 8 | async def test_basic_functionality(self, client): 9 | amm_pool = await create_amm_pool_async(client) 10 | asset = amm_pool["asset"] 11 | asset2 = amm_pool["asset2"] 12 | 13 | amm_info = await client.request( 14 | AMMInfo( 15 | asset=asset, 16 | asset2=asset2, 17 | ) 18 | ) 19 | 20 | self.assertEqual(float(amm_info.result["amm"]["amount"]), 250) 21 | self.assertEqual( 22 | amm_info.result["amm"]["amount2"], 23 | { 24 | "currency": asset2.currency, 25 | "issuer": asset2.issuer, 26 | "value": "250", 27 | }, 28 | ) 29 | -------------------------------------------------------------------------------- /tests/integration/transactions/test_check_cancel.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import ( 3 | sign_and_reliable_submission_async, 4 | test_async_and_sync, 5 | ) 6 | from tests.integration.reusable_values import WALLET 7 | from xrpl.models.response import ResponseStatus 8 | from xrpl.models.transactions import CheckCancel 9 | 10 | ACCOUNT = WALLET.address 11 | 12 | CHECK_ID = "49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0" 13 | 14 | 15 | class TestCheckCancel(IntegrationTestCase): 16 | @test_async_and_sync(globals()) 17 | async def test_all_fields(self, client): 18 | check_cancel = CheckCancel( 19 | account=ACCOUNT, 20 | check_id=CHECK_ID, 21 | ) 22 | response = await sign_and_reliable_submission_async( 23 | check_cancel, WALLET, client 24 | ) 25 | self.assertEqual(response.status, ResponseStatus.SUCCESS) 26 | # This transaction shouldn't actually succeed, because this isn't a real check: 27 | # Docs for tecNO_ENTRY read: 28 | # "The transaction tried to modify a ledger object, such as a Check, 29 | # Payment Channel, or Deposit Preauthorization, but the specified object 30 | # does not exist. It may have already been deleted by a previous 31 | # transaction or the transaction may have an incorrect value in an 32 | # ID field such as CheckID, Channel, Unauthorize." 33 | self.assertEqual(response.result["engine_result"], "tecNO_ENTRY") 34 | -------------------------------------------------------------------------------- /tests/integration/transactions/test_check_cash.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import ( 3 | sign_and_reliable_submission_async, 4 | test_async_and_sync, 5 | ) 6 | from tests.integration.reusable_values import WALLET 7 | from xrpl.models.response import ResponseStatus 8 | from xrpl.models.transactions import CheckCash 9 | 10 | ACCOUNT = WALLET.address 11 | CHECK_ID = "838766BA2B995C00744175F69A1B11E32C3DBC40E64801A4056FCBD657F57334" 12 | AMOUNT = "100000000" 13 | DELIVER_MIN = "100000000" 14 | 15 | 16 | class TestCheckCreate(IntegrationTestCase): 17 | @test_async_and_sync(globals()) 18 | async def test_required_fields_with_amount(self, client): 19 | check_cash = CheckCash( 20 | account=ACCOUNT, 21 | check_id=CHECK_ID, 22 | amount=AMOUNT, 23 | ) 24 | response = await sign_and_reliable_submission_async(check_cash, WALLET, client) 25 | self.assertEqual(response.status, ResponseStatus.SUCCESS) 26 | # Getting `tecNO_ENTRY` codes because using a non-existent check ID 27 | self.assertEqual(response.result["engine_result"], "tecNO_ENTRY") 28 | 29 | @test_async_and_sync(globals()) 30 | async def test_required_fields_with_deliver_min(self, client): 31 | check_cash = CheckCash( 32 | account=ACCOUNT, 33 | check_id=CHECK_ID, 34 | deliver_min=DELIVER_MIN, 35 | ) 36 | response = await sign_and_reliable_submission_async(check_cash, WALLET, client) 37 | self.assertEqual(response.status, ResponseStatus.SUCCESS) 38 | self.assertEqual(response.result["engine_result"], "tecNO_ENTRY") 39 | -------------------------------------------------------------------------------- /tests/integration/transactions/test_check_create.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import ( 3 | sign_and_reliable_submission_async, 4 | test_async_and_sync, 5 | ) 6 | from tests.integration.reusable_values import DESTINATION, WALLET 7 | from xrpl.models.response import ResponseStatus 8 | from xrpl.models.transactions import CheckCreate 9 | 10 | ACCOUNT = WALLET.address 11 | DESTINATION_TAG = 1 12 | SENDMAX = "100000000" 13 | EXPIRATION = 970113521 14 | INVOICE_ID = "6F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B" 15 | 16 | 17 | class TestCheckCreate(IntegrationTestCase): 18 | @test_async_and_sync(globals()) 19 | async def test_all_fields(self, client): 20 | check_create = CheckCreate( 21 | account=ACCOUNT, 22 | destination=DESTINATION.address, 23 | destination_tag=DESTINATION_TAG, 24 | send_max=SENDMAX, 25 | expiration=EXPIRATION, 26 | invoice_id=INVOICE_ID, 27 | ) 28 | response = await sign_and_reliable_submission_async( 29 | check_create, WALLET, client 30 | ) 31 | self.assertEqual(response.status, ResponseStatus.SUCCESS) 32 | self.assertEqual(response.result["engine_result"], "tesSUCCESS") 33 | -------------------------------------------------------------------------------- /tests/integration/transactions/test_did_set.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import ( 3 | sign_and_reliable_submission_async, 4 | test_async_and_sync, 5 | ) 6 | from tests.integration.reusable_values import WALLET 7 | from xrpl.models import AccountObjects, AccountObjectType, DIDSet 8 | from xrpl.models.response import ResponseStatus 9 | 10 | _VALID_FIELD = "1234567890abcdefABCDEF" 11 | 12 | 13 | class TestDIDSet(IntegrationTestCase): 14 | @test_async_and_sync(globals()) 15 | async def test_all_fields(self, client): 16 | tx = DIDSet( 17 | account=WALLET.address, 18 | did_document=_VALID_FIELD, 19 | uri=_VALID_FIELD, 20 | data=_VALID_FIELD, 21 | ) 22 | response = await sign_and_reliable_submission_async(tx, WALLET, client) 23 | self.assertEqual(response.status, ResponseStatus.SUCCESS) 24 | self.assertEqual(response.result["engine_result"], "tesSUCCESS") 25 | 26 | # confirm that the DID was actually created 27 | account_objects_response = await client.request( 28 | AccountObjects(account=WALLET.address, type=AccountObjectType.DID) 29 | ) 30 | self.assertEqual(len(account_objects_response.result["account_objects"]), 1) 31 | -------------------------------------------------------------------------------- /tests/integration/transactions/test_escrow_cancel.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import ( 3 | sign_and_reliable_submission_async, 4 | test_async_and_sync, 5 | ) 6 | from tests.integration.reusable_values import WALLET 7 | from xrpl.models.response import ResponseStatus 8 | from xrpl.models.transactions import EscrowCancel 9 | 10 | ACCOUNT = WALLET.address 11 | OWNER = "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn" 12 | OFFER_SEQUENCE = 7 13 | 14 | 15 | class TestEscrowCancel(IntegrationTestCase): 16 | @test_async_and_sync(globals()) 17 | async def test_all_fields(self, client): 18 | escrow_cancel = EscrowCancel( 19 | account=ACCOUNT, 20 | owner=OWNER, 21 | offer_sequence=OFFER_SEQUENCE, 22 | ) 23 | response = await sign_and_reliable_submission_async( 24 | escrow_cancel, WALLET, client 25 | ) 26 | # Actual engine_result is `tecNO_TARGET since OWNER account doesn't exist 27 | self.assertEqual(response.status, ResponseStatus.SUCCESS) 28 | -------------------------------------------------------------------------------- /tests/integration/transactions/test_escrow_create.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import ( 3 | sign_and_reliable_submission_async, 4 | test_async_and_sync, 5 | ) 6 | from tests.integration.reusable_values import DESTINATION, WALLET 7 | from xrpl.models import EscrowCreate, Ledger 8 | from xrpl.models.response import ResponseStatus 9 | 10 | ACCOUNT = WALLET.address 11 | 12 | AMOUNT = "10000" 13 | CONDITION = ( 14 | "A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100" 15 | ) 16 | DESTINATION_TAG = 23480 17 | SOURCE_TAG = 11747 18 | 19 | 20 | class TestEscrowCreate(IntegrationTestCase): 21 | @test_async_and_sync(globals()) 22 | async def test_all_fields(self, client): 23 | ledger = await client.request(Ledger(ledger_index="validated")) 24 | close_time = ledger.result["ledger"]["close_time"] 25 | escrow_create = EscrowCreate( 26 | account=WALLET.classic_address, 27 | amount=AMOUNT, 28 | destination=DESTINATION.classic_address, 29 | destination_tag=DESTINATION_TAG, 30 | cancel_after=close_time + 3, 31 | finish_after=close_time + 2, 32 | source_tag=SOURCE_TAG, 33 | ) 34 | response = await sign_and_reliable_submission_async( 35 | escrow_create, WALLET, client 36 | ) 37 | self.assertEqual(response.status, ResponseStatus.SUCCESS) 38 | self.assertEqual(response.result["engine_result"], "tesSUCCESS") 39 | -------------------------------------------------------------------------------- /tests/integration/transactions/test_escrow_finish.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import ( 3 | sign_and_reliable_submission_async, 4 | test_async_and_sync, 5 | ) 6 | from tests.integration.reusable_values import WALLET 7 | from xrpl.models.response import ResponseStatus 8 | from xrpl.models.transactions import EscrowFinish 9 | 10 | # Special fee for EscrowFinish transactions that contain a fulfillment. 11 | # See note here: https://xrpl.org/escrowfinish.html 12 | FEE = "600000000" 13 | 14 | ACCOUNT = WALLET.address 15 | OWNER = "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn" 16 | OFFER_SEQUENCE = 7 17 | CONDITION = ( 18 | "A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100" 19 | ) 20 | FULFILLMENT = "A0028000" 21 | 22 | 23 | class TestEscrowFinish(IntegrationTestCase): 24 | @test_async_and_sync(globals()) 25 | async def test_all_fields(self, client): 26 | escrow_finish = EscrowFinish( 27 | account=ACCOUNT, 28 | owner=OWNER, 29 | offer_sequence=OFFER_SEQUENCE, 30 | condition=CONDITION, 31 | fulfillment=FULFILLMENT, 32 | ) 33 | response = await sign_and_reliable_submission_async( 34 | escrow_finish, WALLET, client 35 | ) 36 | # Actual engine_result will be 'tecNO_TARGET' since using non-extant 37 | # account for OWNER 38 | self.assertEqual(response.status, ResponseStatus.SUCCESS) 39 | -------------------------------------------------------------------------------- /tests/integration/transactions/test_mptoken_issuance_create.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import ( 3 | sign_and_reliable_submission_async, 4 | test_async_and_sync, 5 | ) 6 | from tests.integration.reusable_values import WALLET 7 | from xrpl.models.requests.account_objects import AccountObjects, AccountObjectType 8 | from xrpl.models.transactions import MPTokenIssuanceCreate 9 | 10 | 11 | class TestMPTokenIssuanceCreate(IntegrationTestCase): 12 | @test_async_and_sync(globals()) 13 | async def test_basic_functionality(self, client): 14 | tx = MPTokenIssuanceCreate( 15 | account=WALLET.classic_address, 16 | maximum_amount="9223372036854775807", # "7fffffffffffffff" 17 | asset_scale=2, 18 | ) 19 | 20 | response = await sign_and_reliable_submission_async( 21 | tx, 22 | WALLET, 23 | client, 24 | ) 25 | 26 | self.assertTrue(response.is_successful()) 27 | self.assertEqual(response.result["engine_result"], "tesSUCCESS") 28 | 29 | # confirm MPTokenIssuance ledger object was created 30 | account_objects_response = await client.request( 31 | AccountObjects(account=WALLET.address, type=AccountObjectType.MPT_ISSUANCE) 32 | ) 33 | 34 | # subsequent integration tests (sync/async + json/websocket) add one 35 | # MPTokenIssuance object to the account 36 | self.assertTrue(len(account_objects_response.result["account_objects"]) > 0) 37 | -------------------------------------------------------------------------------- /tests/integration/transactions/test_offer_cancel.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import ( 3 | sign_and_reliable_submission_async, 4 | test_async_and_sync, 5 | ) 6 | from tests.integration.reusable_values import OFFER, WALLET 7 | from xrpl.models.transactions import OfferCancel 8 | 9 | 10 | class TestOfferCancel(IntegrationTestCase): 11 | @test_async_and_sync(globals()) 12 | async def test_all_fields(self, client): 13 | response = await sign_and_reliable_submission_async( 14 | OfferCancel( 15 | account=WALLET.address, 16 | offer_sequence=OFFER.result["tx_json"]["Sequence"], 17 | ), 18 | WALLET, 19 | client, 20 | ) 21 | self.assertTrue(response.is_successful()) 22 | # NOTE: offer cancellations are difficult to test because not 23 | # specifying an offer ID to cancel is not considered an error. 24 | # 25 | # This TX will result in a success essentially as long as it is 26 | # correctly formatted. 27 | -------------------------------------------------------------------------------- /tests/integration/transactions/test_payment_channel_claim.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import ( 3 | sign_and_reliable_submission_async, 4 | test_async_and_sync, 5 | ) 6 | from tests.integration.reusable_values import PAYMENT_CHANNEL, WALLET 7 | from xrpl.models.transactions import PaymentChannelClaim 8 | 9 | 10 | class TestPaymentChannelClaim(IntegrationTestCase): 11 | @test_async_and_sync(globals()) 12 | async def test_receiver_claim(self, client): 13 | response = await sign_and_reliable_submission_async( 14 | PaymentChannelClaim( 15 | account=WALLET.address, 16 | channel=PAYMENT_CHANNEL.result["tx_json"]["hash"], 17 | ), 18 | WALLET, 19 | client, 20 | ) 21 | self.assertTrue(response.is_successful()) 22 | -------------------------------------------------------------------------------- /tests/integration/transactions/test_payment_channel_create.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import ( 3 | sign_and_reliable_submission_async, 4 | test_async_and_sync, 5 | ) 6 | from tests.integration.reusable_values import DESTINATION, WALLET 7 | from xrpl.models.transactions import PaymentChannelCreate 8 | 9 | 10 | class TestPaymentChannelCreate(IntegrationTestCase): 11 | @test_async_and_sync(globals()) 12 | async def test_basic_functionality(self, client): 13 | payment_channel = await sign_and_reliable_submission_async( 14 | PaymentChannelCreate( 15 | account=WALLET.address, 16 | amount="1", 17 | destination=DESTINATION.address, 18 | settle_delay=86400, 19 | public_key=WALLET.public_key, 20 | ), 21 | WALLET, 22 | client, 23 | ) 24 | self.assertTrue(payment_channel.is_successful()) 25 | -------------------------------------------------------------------------------- /tests/integration/transactions/test_payment_channel_fund.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import ( 3 | sign_and_reliable_submission_async, 4 | test_async_and_sync, 5 | ) 6 | from tests.integration.reusable_values import PAYMENT_CHANNEL, WALLET 7 | from xrpl.models.transactions import PaymentChannelFund 8 | 9 | 10 | class TestPaymentChannelFund(IntegrationTestCase): 11 | @test_async_and_sync(globals()) 12 | async def test_basic_functionality(self, client): 13 | response = await sign_and_reliable_submission_async( 14 | PaymentChannelFund( 15 | account=WALLET.address, 16 | channel=PAYMENT_CHANNEL.result["tx_json"]["hash"], 17 | amount="1", 18 | ), 19 | WALLET, 20 | client, 21 | ) 22 | self.assertTrue(response.is_successful()) 23 | -------------------------------------------------------------------------------- /tests/integration/transactions/test_set_regular_key.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import ( 3 | sign_and_reliable_submission_async, 4 | test_async_and_sync, 5 | ) 6 | from tests.integration.reusable_values import WALLET 7 | from xrpl.models.transactions import SetRegularKey 8 | from xrpl.wallet import Wallet 9 | 10 | 11 | class TestSetRegularKey(IntegrationTestCase): 12 | @test_async_and_sync(globals()) 13 | async def test_all_fields(self, client): 14 | regular_key = Wallet.create().address 15 | response = await sign_and_reliable_submission_async( 16 | SetRegularKey( 17 | account=WALLET.address, 18 | regular_key=regular_key, 19 | ), 20 | WALLET, 21 | client, 22 | ) 23 | self.assertTrue(response.is_successful()) 24 | -------------------------------------------------------------------------------- /tests/integration/transactions/test_signer_list_set.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import ( 3 | sign_and_reliable_submission_async, 4 | test_async_and_sync, 5 | ) 6 | from tests.integration.reusable_values import WALLET 7 | from xrpl.models.transactions import SignerEntry, SignerListSet 8 | from xrpl.wallet import Wallet 9 | 10 | 11 | class TestSignerListSet(IntegrationTestCase): 12 | @test_async_and_sync(globals()) 13 | async def test_add_signer(self, client): 14 | # sets up another signer for this account 15 | other_signer = Wallet.create() 16 | response = await sign_and_reliable_submission_async( 17 | SignerListSet( 18 | account=WALLET.address, 19 | signer_quorum=1, 20 | signer_entries=[ 21 | SignerEntry( 22 | account=other_signer.address, 23 | signer_weight=1, 24 | ), 25 | ], 26 | ), 27 | WALLET, 28 | client, 29 | ) 30 | self.assertTrue(response.is_successful()) 31 | -------------------------------------------------------------------------------- /tests/integration/transactions/test_ticket_create.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import ( 3 | sign_and_reliable_submission_async, 4 | test_async_and_sync, 5 | ) 6 | from tests.integration.reusable_values import WALLET 7 | from xrpl.models.transactions import TicketCreate 8 | 9 | 10 | class TestTicketCreate(IntegrationTestCase): 11 | @test_async_and_sync(globals()) 12 | async def test_basic_functionality(self, client): 13 | response = await sign_and_reliable_submission_async( 14 | TicketCreate( 15 | account=WALLET.address, 16 | ticket_count=2, 17 | ), 18 | WALLET, 19 | client, 20 | ) 21 | self.assertTrue(response.is_successful()) 22 | self.assertEqual(response.result["engine_result"], "tesSUCCESS") 23 | -------------------------------------------------------------------------------- /tests/integration/transactions/test_xchain_commit.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import ( 3 | sign_and_reliable_submission_async, 4 | test_async_and_sync, 5 | ) 6 | from tests.integration.reusable_values import BRIDGE, WALLET 7 | from xrpl.models import AccountInfo, XChainCommit 8 | 9 | 10 | class TestXChainCommit(IntegrationTestCase): 11 | @test_async_and_sync(globals()) 12 | async def test_basic_functionality(self, client): 13 | locking_chain_door = BRIDGE.xchain_bridge.locking_chain_door 14 | account_info1 = await client.request(AccountInfo(account=locking_chain_door)) 15 | initial_balance = int(account_info1.result["account_data"]["Balance"]) 16 | amount = 1000000 17 | 18 | response = await sign_and_reliable_submission_async( 19 | XChainCommit( 20 | account=WALLET.classic_address, 21 | xchain_bridge=BRIDGE.xchain_bridge, 22 | amount=str(amount), 23 | xchain_claim_id=1, 24 | ), 25 | WALLET, 26 | client, 27 | ) 28 | self.assertTrue(response.is_successful()) 29 | self.assertEqual(response.result["engine_result"], "tesSUCCESS") 30 | 31 | account_info2 = await client.request(AccountInfo(account=locking_chain_door)) 32 | final_balance = int(account_info2.result["account_data"]["Balance"]) 33 | self.assertEqual(final_balance, initial_balance + amount) 34 | -------------------------------------------------------------------------------- /tests/integration/transactions/test_xchain_create_claim_id.py: -------------------------------------------------------------------------------- 1 | from tests.integration.integration_test_case import IntegrationTestCase 2 | from tests.integration.it_utils import ( 3 | fund_wallet_async, 4 | sign_and_reliable_submission_async, 5 | test_async_and_sync, 6 | ) 7 | from tests.integration.reusable_values import BRIDGE 8 | from xrpl.models import AccountObjects, AccountObjectType, XChainCreateClaimID 9 | from xrpl.wallet import Wallet 10 | 11 | 12 | class TestXChainCreateClaimID(IntegrationTestCase): 13 | @test_async_and_sync(globals()) 14 | async def test_basic_functionality(self, client): 15 | account = Wallet.create() 16 | await fund_wallet_async(account) 17 | response = await sign_and_reliable_submission_async( 18 | XChainCreateClaimID( 19 | account=account.classic_address, 20 | xchain_bridge=BRIDGE.xchain_bridge, 21 | other_chain_source=Wallet.create().classic_address, 22 | signature_reward=BRIDGE.signature_reward, 23 | ), 24 | account, 25 | client, 26 | ) 27 | self.assertTrue(response.is_successful()) 28 | self.assertEqual(response.result["engine_result"], "tesSUCCESS") 29 | 30 | account_objects_response = await client.request( 31 | AccountObjects( 32 | account=account.classic_address, 33 | type=AccountObjectType.XCHAIN_OWNED_CLAIM_ID, 34 | ) 35 | ) 36 | self.assertEqual(len(account_objects_response.result["account_objects"]), 1) 37 | -------------------------------------------------------------------------------- /tests/unit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/unit/__init__.py -------------------------------------------------------------------------------- /tests/unit/asyn/__init__.py: -------------------------------------------------------------------------------- 1 | # We named this module `asyn` instead of `asyncio` to get around a name 2 | # collision with the `asyncio` library when running integration tests. Seems 3 | # to be an issue with `unittest discover` and the fact that each directory 4 | # needs to be its own module, meaning that if this were called `asyncio` 5 | # then it does actually conflict with the standard library.... 6 | -------------------------------------------------------------------------------- /tests/unit/asyn/ledger/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/unit/asyn/ledger/__init__.py -------------------------------------------------------------------------------- /tests/unit/asyn/wallet/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/unit/asyn/wallet/__init__.py -------------------------------------------------------------------------------- /tests/unit/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/unit/core/__init__.py -------------------------------------------------------------------------------- /tests/unit/core/addresscodec/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/unit/core/addresscodec/__init__.py -------------------------------------------------------------------------------- /tests/unit/core/binarycodec/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/unit/core/binarycodec/__init__.py -------------------------------------------------------------------------------- /tests/unit/core/binarycodec/test_binary_serializer.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from xrpl.core.binarycodec.binary_wrappers.binary_parser import BinaryParser 4 | from xrpl.core.binarycodec.binary_wrappers.binary_serializer import BinarySerializer 5 | from xrpl.core.binarycodec.types.blob import Blob 6 | 7 | 8 | class TestBinarySerializer(TestCase): 9 | # This is currently a sanity check for private _encode_variable_length_prefix, 10 | # which is called by BinarySerializer.write_length_encoded 11 | def test_write_length_encoded(self): 12 | # length ranges: 0 - 192, 193 - 12480, 12481 - 918744 13 | for case in [100, 1000, 20_000]: 14 | bytestring = "A2" * case 15 | blob = Blob.from_value(bytestring) 16 | self.assertEqual(len(blob), case) # sanity check 17 | binary_serializer = BinarySerializer() 18 | binary_serializer.write_length_encoded(blob) 19 | 20 | binary_parser = BinaryParser(bytes(binary_serializer).hex()) 21 | decoded_length = binary_parser._read_length_prefix() 22 | self.assertEqual(case, decoded_length) 23 | -------------------------------------------------------------------------------- /tests/unit/core/binarycodec/test_field_id_codec.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | import xrpl.core.binarycodec.field_id_codec as field_id_codec 4 | from tests.unit.core.binarycodec.fixtures import data_driven_fixtures 5 | 6 | 7 | class TestFieldIDCodec(TestCase): 8 | """`See FieldIDs `_.""" 9 | 10 | def setUp(self): 11 | self.field_tests = data_driven_fixtures.get_field_tests() 12 | 13 | def test_encode(self): 14 | for test in self.field_tests: 15 | # .hex().upper() just formats the resulting bytes for comparison 16 | # with upper case hex string in fixture data 17 | self.assertEqual( 18 | test.expected_hex, field_id_codec.encode(test.name).hex().upper() 19 | ) 20 | 21 | def test_decode(self): 22 | for test in self.field_tests: 23 | self.assertEqual(test.name, field_id_codec.decode(test.expected_hex)) 24 | -------------------------------------------------------------------------------- /tests/unit/core/binarycodec/types/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/unit/core/binarycodec/types/__init__.py -------------------------------------------------------------------------------- /tests/unit/core/binarycodec/types/test_account_id.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from xrpl.core.binarycodec import XRPLBinaryCodecException 4 | from xrpl.core.binarycodec.types.account_id import AccountID 5 | 6 | HEX_ENCODING = "5E7B112523F68D2F5E879DB4EAC51C6698A69304" 7 | BASE58_ENCODING = "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59" 8 | 9 | 10 | class TestAccountID(TestCase): 11 | def test_from_value_hex(self): 12 | account_id = AccountID.from_value(HEX_ENCODING) 13 | self.assertEqual(account_id.to_json(), BASE58_ENCODING) 14 | 15 | def test_from_value_base58(self): 16 | account_id = AccountID.from_value(BASE58_ENCODING) 17 | # Note that I converted the hex to uppercase here... 18 | # We may want to decide if we want the implemention of `to_hex` in 19 | # SerializedType to return uppercase hex by default. 20 | self.assertEqual(account_id.to_hex(), HEX_ENCODING) 21 | 22 | def test_raises_invalid_value_type(self): 23 | invalid_value = 30 24 | self.assertRaises(XRPLBinaryCodecException, AccountID.from_value, invalid_value) 25 | -------------------------------------------------------------------------------- /tests/unit/core/binarycodec/types/test_blob.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from xrpl.core.binarycodec import XRPLBinaryCodecException 4 | from xrpl.core.binarycodec.types.blob import Blob 5 | 6 | 7 | class TestBlob(TestCase): 8 | def test_from_value(self): 9 | value = "00AA" 10 | value_bytes = bytes.fromhex(value) 11 | 12 | blob1 = Blob.from_value(value) 13 | blob2 = Blob(value_bytes) 14 | 15 | self.assertEqual(blob1.buffer, blob2.buffer) 16 | 17 | def test_raises_invalid_value_type(self): 18 | invalid_value = [1, 2, 3] 19 | self.assertRaises(XRPLBinaryCodecException, Blob.from_value, invalid_value) 20 | -------------------------------------------------------------------------------- /tests/unit/core/binarycodec/types/test_vector256.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from xrpl.core.binarycodec import XRPLBinaryCodecException 4 | from xrpl.core.binarycodec.binary_wrappers import BinaryParser 5 | from xrpl.core.binarycodec.types.vector256 import Vector256 6 | 7 | HASH1 = "42426C4D4F1009EE67080A9B7965B44656D7714D104A72F9B4369F97ABF044EE" 8 | HASH2 = "4C97EBA926031A7CF7D7B36FDE3ED66DDA5421192D63DE53FFB46E43B9DC8373" 9 | HASH_LIST = [HASH1, HASH2] 10 | SERIALIZED = HASH1 + HASH2 11 | 12 | 13 | class TestVector256(TestCase): 14 | def test_from_value(self): 15 | vector256_object = Vector256.from_value(HASH_LIST) 16 | self.assertEqual(vector256_object.to_hex(), SERIALIZED) 17 | 18 | def test_from_parser(self): 19 | parser = BinaryParser(SERIALIZED) 20 | vector256_object = Vector256.from_parser(parser) 21 | self.assertEqual(vector256_object.to_hex(), SERIALIZED) 22 | 23 | def test_to_json(self): 24 | vector256_object = Vector256.from_value(HASH_LIST) 25 | self.assertEqual(vector256_object.to_json(), HASH_LIST) 26 | 27 | def test_raises_invalid_value_type(self): 28 | invalid_value = 1 29 | self.assertRaises(XRPLBinaryCodecException, Vector256.from_value, invalid_value) 30 | -------------------------------------------------------------------------------- /tests/unit/core/keypairs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/unit/core/keypairs/__init__.py -------------------------------------------------------------------------------- /tests/unit/models/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/unit/models/__init__.py -------------------------------------------------------------------------------- /tests/unit/models/amounts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/unit/models/amounts/__init__.py -------------------------------------------------------------------------------- /tests/unit/models/amounts/test_issued_currency_amount.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from xrpl.models.amounts import IssuedCurrencyAmount 4 | from xrpl.models.currencies import IssuedCurrency 5 | 6 | _ISSUER = "r9LqNeG6qHxjeUocjvVki2XR35weJ9mZgQ" 7 | 8 | 9 | class TestIssuedCurrencyAmount(TestCase): 10 | def test_to_currency(self): 11 | currency = "USD" 12 | amount = "12" 13 | expected = IssuedCurrency(currency=currency, issuer=_ISSUER) 14 | 15 | issued_currency_amount = IssuedCurrencyAmount( 16 | currency=currency, issuer=_ISSUER, value=amount 17 | ) 18 | result = issued_currency_amount.to_currency() 19 | 20 | self.assertEqual(result, expected) 21 | -------------------------------------------------------------------------------- /tests/unit/models/currencies/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/unit/models/currencies/__init__.py -------------------------------------------------------------------------------- /tests/unit/models/currencies/test_mpt_currency.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from xrpl.models.currencies import MPTCurrency 4 | from xrpl.models.exceptions import XRPLModelException 5 | 6 | _MPTID = "00002403C84A0A28E0190E208E982C352BBD5006600555CF" 7 | 8 | 9 | class TestMPTCurrency(TestCase): 10 | def test_correct_mptid_format(self): 11 | obj = MPTCurrency( 12 | mpt_issuance_id=_MPTID, 13 | ) 14 | self.assertTrue(obj.is_valid()) 15 | 16 | def test_lower_mptid_format(self): 17 | obj = MPTCurrency( 18 | mpt_issuance_id=_MPTID.lower(), 19 | ) 20 | self.assertTrue(obj.is_valid()) 21 | 22 | def test_invalid_length(self): 23 | with self.assertRaises(XRPLModelException): 24 | MPTCurrency(mpt_issuance_id=_MPTID[:40]) 25 | 26 | with self.assertRaises(XRPLModelException): 27 | MPTCurrency(mpt_issuance_id=_MPTID + "AA") 28 | 29 | def test_incorrect_hex_format(self): 30 | # the "+" is not allowed in a currency format" 31 | with self.assertRaises(XRPLModelException): 32 | MPTCurrency( 33 | mpt_issuance_id="ABCD" * 11 + "XXXX", 34 | ) 35 | 36 | def test_to_amount(self): 37 | amount = "12" 38 | MPT_currency = MPTCurrency(mpt_issuance_id=_MPTID) 39 | MPT_currency_amount = MPT_currency.to_amount(amount) 40 | 41 | self.assertEqual(MPT_currency_amount.mpt_issuance_id, _MPTID) 42 | self.assertEqual(MPT_currency_amount.value, amount) 43 | -------------------------------------------------------------------------------- /tests/unit/models/currencies/test_xrp.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from xrpl.models.currencies import XRP 4 | from xrpl.utils import xrp_to_drops 5 | 6 | 7 | class TestXRP(TestCase): 8 | def test_to_dict(self): 9 | self.assertEqual(XRP().to_dict()["currency"], "XRP") 10 | 11 | def test_to_amount(self): 12 | amount = 12 13 | expected = xrp_to_drops(amount) 14 | result = XRP().to_amount(amount) 15 | 16 | self.assertEqual(result, expected) 17 | -------------------------------------------------------------------------------- /tests/unit/models/requests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/unit/models/requests/__init__.py -------------------------------------------------------------------------------- /tests/unit/models/requests/test_amm_info.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from xrpl.models.currencies import XRP, IssuedCurrency 4 | from xrpl.models.exceptions import XRPLModelException 5 | from xrpl.models.requests import AMMInfo 6 | from xrpl.models.requests.request import _DEFAULT_API_VERSION 7 | 8 | _ASSET = XRP() 9 | _ASSET_2 = IssuedCurrency(currency="USD", issuer="rN6zcSynkRnf8zcgTVrRL8K7r4ovE7J4Zj") 10 | _ACCOUNT = _ASSET_2.issuer 11 | 12 | 13 | class TestAMMInfo(TestCase): 14 | def test_populate_api_version_field(self): 15 | request = AMMInfo( 16 | asset=_ASSET, 17 | asset2=_ASSET_2, 18 | ) 19 | self.assertEqual(request.api_version, _DEFAULT_API_VERSION) 20 | self.assertTrue(request.is_valid()) 21 | 22 | def test_asset_asset2(self): 23 | request = AMMInfo( 24 | asset=_ASSET, 25 | asset2=_ASSET_2, 26 | ) 27 | self.assertTrue(request.is_valid()) 28 | 29 | def test_amount(self): 30 | request = AMMInfo( 31 | amm_account=_ACCOUNT, 32 | ) 33 | self.assertTrue(request.is_valid()) 34 | 35 | def test_all_three(self): 36 | with self.assertRaises(XRPLModelException): 37 | AMMInfo( 38 | amm_account=_ACCOUNT, 39 | asset=_ASSET, 40 | asset2=_ASSET_2, 41 | ) 42 | 43 | def test_only_asset(self): 44 | with self.assertRaises(XRPLModelException): 45 | AMMInfo( 46 | asset=_ASSET, 47 | ) 48 | 49 | def test_only_one_asset2(self): 50 | with self.assertRaises(XRPLModelException): 51 | AMMInfo( 52 | asset2=_ASSET_2, 53 | ) 54 | -------------------------------------------------------------------------------- /tests/unit/models/requests/test_deposit_authorized.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from xrpl.models import DepositAuthorized 4 | 5 | 6 | class TestDepositAuthorized(TestCase): 7 | def test_valid(self): 8 | req = DepositAuthorized( 9 | source_account="srcAccount", 10 | destination_account="dstAccount", 11 | credentials=[ 12 | "EA85602C1B41F6F1F5E83C0E6B87142FB8957BD209469E4CC347BA2D0C26F66A" 13 | ], 14 | ) 15 | self.assertTrue(req.is_valid()) 16 | -------------------------------------------------------------------------------- /tests/unit/models/requests/test_tx.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from xrpl.models.exceptions import XRPLModelException 4 | from xrpl.models.requests import Tx 5 | 6 | _TRANSACTION_HASH = "C53ECF838647FA5A4C780377025FEC7999AB4182590510CA461444B207AB74A9" 7 | _CTID = "C005523E00000000" 8 | 9 | 10 | class TestTx(TestCase): 11 | def test_invalid_input_ctid_and_txn_hash(self): 12 | with self.assertRaises(XRPLModelException): 13 | Tx(transaction=_TRANSACTION_HASH, ctid=_CTID) 14 | 15 | # Note: This test merely verifies the semantic correctness of the Request. 16 | # It does not verify if the specified CTID exists. 17 | def test_valid_ctid(self): 18 | request = Tx(ctid=_CTID) 19 | self.assertTrue(request.is_valid()) 20 | 21 | def test_valid_txn_hash(self): 22 | request = Tx(transaction=_TRANSACTION_HASH) 23 | self.assertTrue(request.is_valid()) 24 | -------------------------------------------------------------------------------- /tests/unit/models/transactions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/unit/models/transactions/__init__.py -------------------------------------------------------------------------------- /tests/unit/models/transactions/test_amm_delete.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from xrpl.models.currencies import XRP, IssuedCurrency 4 | from xrpl.models.transactions import AMMDelete 5 | 6 | 7 | class TestAMMDeposit(TestCase): 8 | def test_tx_valid(self): 9 | tx = AMMDelete( 10 | account="r9LqNeG6qHxjeUocjvVki2XR35weJ9mZgQ", 11 | sequence=1337, 12 | asset=XRP(), 13 | asset2=IssuedCurrency( 14 | currency="ETH", issuer="rpGtkFRXhgVaBzC5XCR7gyE2AZN5SN3SEW" 15 | ), 16 | ) 17 | self.assertTrue(tx.is_valid()) 18 | -------------------------------------------------------------------------------- /tests/unit/models/transactions/test_amm_vote.py: -------------------------------------------------------------------------------- 1 | from sys import maxsize 2 | from unittest import TestCase 3 | 4 | from xrpl.models.currencies import XRP, IssuedCurrency 5 | from xrpl.models.exceptions import XRPLModelException 6 | from xrpl.models.transactions import AMMVote 7 | 8 | _ACCOUNT = "r9LqNeG6qHxjeUocjvVki2XR35weJ9mZgQ" 9 | _ASSET = XRP() 10 | _ASSET2 = IssuedCurrency(currency="ETH", issuer="rpGtkFRXhgVaBzC5XCR7gyE2AZN5SN3SEW") 11 | _TRADING_FEE = 234 12 | 13 | 14 | class TestAMMVote(TestCase): 15 | def test_tx_valid(self): 16 | tx = AMMVote( 17 | account=_ACCOUNT, 18 | asset=_ASSET, 19 | asset2=_ASSET2, 20 | trading_fee=_TRADING_FEE, 21 | ) 22 | self.assertTrue(tx.is_valid()) 23 | 24 | def test_trading_fee_too_high(self): 25 | with self.assertRaises(XRPLModelException) as error: 26 | AMMVote( 27 | account=_ACCOUNT, 28 | asset=_ASSET, 29 | asset2=_ASSET2, 30 | trading_fee=maxsize, 31 | ) 32 | self.assertEqual( 33 | error.exception.args[0], 34 | "{'trading_fee': 'Must be between 0 and 1000'}", 35 | ) 36 | 37 | def test_trading_fee_negative_number(self): 38 | with self.assertRaises(XRPLModelException) as error: 39 | AMMVote( 40 | account=_ACCOUNT, 41 | asset=_ASSET, 42 | asset2=_ASSET2, 43 | trading_fee=-1, 44 | ) 45 | self.assertEqual( 46 | error.exception.args[0], 47 | "{'trading_fee': 'Must be between 0 and 1000'}", 48 | ) 49 | -------------------------------------------------------------------------------- /tests/unit/models/transactions/test_batch.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from xrpl.models import Batch, BatchFlag, Payment, TransactionFlag 4 | from xrpl.models.exceptions import XRPLModelException 5 | 6 | _ACCOUNT = "r9LqNeG6qHxjeUocjvVki2XR35weJ9mZgQ" 7 | _DESTINATION = "rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg" 8 | 9 | 10 | class TestBatch(TestCase): 11 | def test_basic(self): 12 | payment = Payment( 13 | account=_ACCOUNT, 14 | amount="1", 15 | destination=_DESTINATION, 16 | ) 17 | batch = Batch( 18 | account=_ACCOUNT, 19 | flags=BatchFlag.TF_ALL_OR_NOTHING, 20 | raw_transactions=[payment, payment], 21 | ) 22 | self.assertTrue(batch.is_valid()) 23 | self.assertTrue( 24 | batch.raw_transactions[0].has_flag(TransactionFlag.TF_INNER_BATCH_TXN) 25 | ) 26 | self.assertTrue( 27 | batch.raw_transactions[1].has_flag(TransactionFlag.TF_INNER_BATCH_TXN) 28 | ) 29 | 30 | def test_too_few_inner_transactions(self): 31 | payment = Payment( 32 | account=_ACCOUNT, 33 | amount="1", 34 | destination=_DESTINATION, 35 | ) 36 | with self.assertRaises(XRPLModelException): 37 | Batch( 38 | account=_ACCOUNT, 39 | flags=BatchFlag.TF_ALL_OR_NOTHING, 40 | raw_transactions=[payment], 41 | ) 42 | -------------------------------------------------------------------------------- /tests/unit/models/transactions/test_check_cash.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from xrpl.models.exceptions import XRPLModelException 4 | from xrpl.models.transactions.check_cash import CheckCash 5 | 6 | _ACCOUNT = "r9LqNeG6qHxjeUocjvVki2XR35weJ9mZgQ" 7 | _FEE = "0.00001" 8 | _SEQUENCE = 19048 9 | _CHECK_ID = "838766BA2B995C00744175F69A1B11E32C3DBC40E64801A4056FCBD657F57334" 10 | _AMOUNT = "300" 11 | 12 | 13 | class TestCheckCash(TestCase): 14 | def test_amount_and_deliver_min_is_invalid(self): 15 | with self.assertRaises(XRPLModelException): 16 | CheckCash( 17 | account=_ACCOUNT, 18 | fee=_FEE, 19 | sequence=_SEQUENCE, 20 | check_id=_CHECK_ID, 21 | amount=_AMOUNT, 22 | deliver_min=_AMOUNT, 23 | ) 24 | 25 | def test_neither_amount_not_deliver_min_is_invalid(self): 26 | with self.assertRaises(XRPLModelException): 27 | CheckCash( 28 | account=_ACCOUNT, 29 | fee=_FEE, 30 | sequence=_SEQUENCE, 31 | check_id=_CHECK_ID, 32 | ) 33 | 34 | def test_amount_without_deliver_min_is_valid(self): 35 | tx = CheckCash( 36 | account=_ACCOUNT, 37 | fee=_FEE, 38 | sequence=_SEQUENCE, 39 | check_id=_CHECK_ID, 40 | amount=_AMOUNT, 41 | ) 42 | self.assertTrue(tx.is_valid()) 43 | 44 | def test_deliver_min_without_amount_is_valid(self): 45 | tx = CheckCash( 46 | account=_ACCOUNT, 47 | fee=_FEE, 48 | sequence=_SEQUENCE, 49 | check_id=_CHECK_ID, 50 | deliver_min=_AMOUNT, 51 | ) 52 | self.assertTrue(tx.is_valid()) 53 | -------------------------------------------------------------------------------- /tests/unit/models/transactions/test_did_delete.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from xrpl.models import DIDDelete 4 | 5 | _ACCOUNT = "r9LqNeG6qHxjeUocjvVki2XR35weJ9mZgQ" 6 | 7 | 8 | class TestDIDDelete(TestCase): 9 | def test_valid(self): 10 | tx = DIDDelete( 11 | account=_ACCOUNT, 12 | ) 13 | self.assertTrue(tx.is_valid()) 14 | 15 | def test_invalid(self): 16 | with self.assertRaises(TypeError): 17 | DIDDelete(account=_ACCOUNT, field="invalid") 18 | -------------------------------------------------------------------------------- /tests/unit/models/transactions/test_escrow_create.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from xrpl.models.exceptions import XRPLModelException 4 | from xrpl.models.transactions import EscrowCreate 5 | 6 | 7 | class TestEscrowCreate(TestCase): 8 | def test_final_after_less_than_cancel_after(self): 9 | account = "r9LqNeG6qHxjeUocjvVki2XR35weJ9mZgQ" 10 | amount = "amount" 11 | cancel_after = 1 12 | finish_after = 2 13 | destination = "destination" 14 | fee = "0.00001" 15 | sequence = 19048 16 | 17 | with self.assertRaises(XRPLModelException): 18 | EscrowCreate( 19 | account=account, 20 | amount=amount, 21 | cancel_after=cancel_after, 22 | destination=destination, 23 | fee=fee, 24 | finish_after=finish_after, 25 | sequence=sequence, 26 | ) 27 | -------------------------------------------------------------------------------- /tests/unit/models/transactions/test_mptoken_authorize.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from xrpl.models.transactions.mptoken_authorize import MPTokenAuthorize 4 | 5 | _ACCOUNT = "r9LqNeG6qHxjeUocjvVki2XR35weJ9mZgQ" 6 | _TOKEN_ID = "000004C463C52827307480341125DA0577DEFC38405B0E3E" 7 | 8 | 9 | class TestMPTokenAuthorize(TestCase): 10 | def test_tx_is_valid(self): 11 | tx = MPTokenAuthorize( 12 | account=_ACCOUNT, 13 | mptoken_issuance_id=_TOKEN_ID, 14 | ) 15 | self.assertTrue(tx.is_valid()) 16 | 17 | def test_holder(self): 18 | tx = MPTokenAuthorize( 19 | account=_ACCOUNT, 20 | holder="rajgkBmMxmz161r8bWYH7CQAFZP5bA9oSG", 21 | mptoken_issuance_id=_TOKEN_ID, 22 | ) 23 | self.assertTrue(tx.is_valid()) 24 | -------------------------------------------------------------------------------- /tests/unit/models/transactions/test_mptoken_issuance_destroy.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from xrpl.models.transactions.mptoken_issuance_destroy import MPTokenIssuanceDestroy 4 | 5 | _ACCOUNT = "r9LqNeG6qHxjeUocjvVki2XR35weJ9mZgQ" 6 | _TOKEN_ID = "000004C463C52827307480341125DA0577DEFC38405B0E3E" 7 | 8 | 9 | class TestMPTokenIssuanceDestroy(TestCase): 10 | def test_tx_is_valid(self): 11 | tx = MPTokenIssuanceDestroy( 12 | account=_ACCOUNT, 13 | mptoken_issuance_id=_TOKEN_ID, 14 | ) 15 | self.assertTrue(tx.is_valid()) 16 | -------------------------------------------------------------------------------- /tests/unit/models/transactions/test_nftoken_cancel_offer.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from xrpl.models.exceptions import XRPLModelException 4 | from xrpl.models.transactions import NFTokenCancelOffer 5 | 6 | _ACCOUNT = "r9LqNeG6qHxjeUocjvVki2XR35weJ9mZgQ" 7 | _FEE = "0.00001" 8 | _SEQUENCE = 19048 9 | _NFTOKEN_OFFER = "3A35B2A4EDF2F3BEF5323C895259957405F0B8F8F6D6E97E46BFDB2484261AF7" 10 | 11 | 12 | class TestNFTokenCancelOffer(TestCase): 13 | def test_empty_nftoken_offers(self): 14 | with self.assertRaises(XRPLModelException): 15 | NFTokenCancelOffer( 16 | account=_ACCOUNT, 17 | fee=_FEE, 18 | sequence=_SEQUENCE, 19 | nftoken_offers=[], 20 | ) 21 | 22 | def test_present_nftoken_offers(self): 23 | tx = NFTokenCancelOffer( 24 | account=_ACCOUNT, 25 | fee=_FEE, 26 | sequence=_SEQUENCE, 27 | nftoken_offers=[_NFTOKEN_OFFER], 28 | ) 29 | self.assertTrue(tx.is_valid()) 30 | -------------------------------------------------------------------------------- /tests/unit/models/transactions/test_nftoken_mint.py: -------------------------------------------------------------------------------- 1 | from sys import maxsize 2 | from unittest import TestCase 3 | 4 | from xrpl.models.exceptions import XRPLModelException 5 | from xrpl.models.transactions import NFTokenMint 6 | 7 | _ACCOUNT = "r9LqNeG6qHxjeUocjvVki2XR35weJ9mZgQ" 8 | _FEE = "0.00001" 9 | _SEQUENCE = 19048 10 | 11 | 12 | class TestNFTokenMint(TestCase): 13 | def test_issuer_is_account(self): 14 | with self.assertRaises(XRPLModelException): 15 | NFTokenMint( 16 | account=_ACCOUNT, 17 | fee=_FEE, 18 | sequence=_SEQUENCE, 19 | nftoken_taxon=0, 20 | issuer=_ACCOUNT, 21 | ) 22 | 23 | def test_transfer_fee_too_high(self): 24 | with self.assertRaises(XRPLModelException): 25 | NFTokenMint( 26 | account=_ACCOUNT, 27 | fee=_FEE, 28 | sequence=_SEQUENCE, 29 | nftoken_taxon=0, 30 | transfer_fee=maxsize, 31 | ) 32 | 33 | def test_uri_too_long(self): 34 | with self.assertRaises(XRPLModelException): 35 | NFTokenMint( 36 | account=_ACCOUNT, 37 | fee=_FEE, 38 | sequence=_SEQUENCE, 39 | nftoken_taxon=0, 40 | uri=_ACCOUNT * 1000, 41 | ) 42 | -------------------------------------------------------------------------------- /tests/unit/models/transactions/test_oracle_delete.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from xrpl.models.transactions import OracleDelete 4 | 5 | _ACCOUNT = "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW" 6 | 7 | 8 | class TestDeleteOracle(TestCase): 9 | def test_valid(self): 10 | tx = OracleDelete( 11 | account=_ACCOUNT, 12 | oracle_document_id=1, 13 | ) 14 | self.assertTrue(tx.is_valid()) 15 | -------------------------------------------------------------------------------- /tests/unit/models/transactions/test_xchain_create_claim_id.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from xrpl.models import XRP, XChainBridge, XChainCreateClaimID, XRPLModelException 4 | 5 | _ACCOUNT = "r9LqNeG6qHxjeUocjvVki2XR35weJ9mZgQ" 6 | _ACCOUNT2 = "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo" 7 | 8 | _ISSUER = "rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf" 9 | _GENESIS = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh" 10 | 11 | _SOURCE = "rJrRMgiRgrU6hDF4pgu5DXQdWyPbY35ErN" 12 | _SIGNATURE_REWARD = "200" 13 | 14 | _XRP_BRIDGE = XChainBridge( 15 | locking_chain_door=_ACCOUNT, 16 | locking_chain_issue=XRP(), 17 | issuing_chain_door=_GENESIS, 18 | issuing_chain_issue=XRP(), 19 | ) 20 | 21 | 22 | class TestXChainCreateClaimID(TestCase): 23 | def test_successful(self): 24 | XChainCreateClaimID( 25 | account=_ACCOUNT, 26 | xchain_bridge=_XRP_BRIDGE, 27 | signature_reward=_SIGNATURE_REWARD, 28 | other_chain_source=_SOURCE, 29 | ) 30 | 31 | def test_bad_signature_reward(self): 32 | with self.assertRaises(XRPLModelException): 33 | XChainCreateClaimID( 34 | account=_ACCOUNT, 35 | xchain_bridge=_XRP_BRIDGE, 36 | signature_reward="hello", 37 | other_chain_source=_SOURCE, 38 | ) 39 | 40 | def test_bad_other_chain_source(self): 41 | with self.assertRaises(XRPLModelException): 42 | XChainCreateClaimID( 43 | account=_ACCOUNT, 44 | xchain_bridge=_XRP_BRIDGE, 45 | signature_reward=_SIGNATURE_REWARD, 46 | other_chain_source="hello", 47 | ) 48 | -------------------------------------------------------------------------------- /tests/unit/transaction/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/unit/transaction/__init__.py -------------------------------------------------------------------------------- /tests/unit/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/unit/utils/__init__.py -------------------------------------------------------------------------------- /tests/unit/utils/test_get_nftoken_id.py: -------------------------------------------------------------------------------- 1 | """Test the get_nftoken_id util.""" 2 | 3 | from __future__ import annotations 4 | 5 | import json 6 | from unittest import TestCase 7 | 8 | from xrpl.utils import get_nftoken_id 9 | 10 | path_to_json = "tests/unit/utils/txn_parser/transaction_jsons/" 11 | with open(path_to_json + "nftokenmint_response1.json", "r") as infile: 12 | nftokenmint_response1 = json.load(infile) 13 | with open(path_to_json + "nftokenmint_response2.json", "r") as infile: 14 | nftokenmint_response2 = json.load(infile) 15 | with open(path_to_json + "offer_cancelled.json", "r") as infile: 16 | wrong_fixture = json.load(infile) 17 | 18 | 19 | class TestGetNFTokenID(TestCase): 20 | """Test get_nftoken_id.""" 21 | 22 | def test_decoding_a_valid_nftoken_id(self): 23 | result = get_nftoken_id(nftokenmint_response1["meta"]) 24 | expected_nftoken_id = ( 25 | "00081388DC1AB4937C899037B2FDFC3CB20F6F64E73120BB5F8AA66A00000228" 26 | ) 27 | self.assertEqual(result, expected_nftoken_id) 28 | 29 | def test_a_different_valid_nftokenmint_metadata(self): 30 | result = get_nftoken_id(nftokenmint_response2["meta"]) 31 | expected_nftoken_id = ( 32 | "0008125CBE4B401B2F62ED35CC67362165AA813CCA06316FFA766254000003EE" 33 | ) 34 | self.assertEqual(result, expected_nftoken_id) 35 | 36 | def test_error_with_wrong_tx_metadata(self) -> None: 37 | self.assertIsNone(get_nftoken_id(wrong_fixture["meta"])) 38 | 39 | def test_error_when_given_raw_instead_of_meta(self) -> None: 40 | self.assertRaises(TypeError, lambda: get_nftoken_id(nftokenmint_response1)) 41 | -------------------------------------------------------------------------------- /tests/unit/utils/test_get_xchain_claim_id.py: -------------------------------------------------------------------------------- 1 | """Test the get_xchain_claim_id util.""" 2 | 3 | from __future__ import annotations 4 | 5 | import json 6 | from unittest import TestCase 7 | 8 | from xrpl.utils import get_xchain_claim_id 9 | 10 | path_to_json = "tests/unit/utils/txn_parser/transaction_jsons/" 11 | with open(path_to_json + "XChainCreateClaimID.json", "r") as f: 12 | fixture = json.load(f) 13 | with open(path_to_json + "XChainCreateClaimID2.json", "r") as f: 14 | fixture2 = json.load(f) 15 | with open(path_to_json + "nftokenmint_response1.json", "r") as f: 16 | wrong_fixture = json.load(f) 17 | 18 | 19 | class TestGetXChainClaimID(TestCase): 20 | """Test get_xchain_claim_id.""" 21 | 22 | def test_decoding_a_valid_xchain_claim_id(self): 23 | result = get_xchain_claim_id(fixture["meta"]) 24 | expected_xchain_claim_id = "b0" 25 | self.assertEqual(result, expected_xchain_claim_id) 26 | 27 | def test_a_different_valid_xchain_claim_id(self): 28 | result = get_xchain_claim_id(fixture2["meta"]) 29 | expected_xchain_claim_id = "ac" 30 | self.assertEqual(result, expected_xchain_claim_id) 31 | 32 | def test_error_with_wrong_tx_metadata(self) -> None: 33 | self.assertRaises(TypeError, lambda: get_xchain_claim_id(wrong_fixture["meta"])) 34 | 35 | def test_error_with_raw_instead_of_meta(self) -> None: 36 | self.assertRaises(TypeError, lambda: get_xchain_claim_id(fixture)) 37 | -------------------------------------------------------------------------------- /tests/unit/utils/test_parse_nftoken_id.py: -------------------------------------------------------------------------------- 1 | """Test the parse_nftoken_id util.""" 2 | 3 | from __future__ import annotations 4 | 5 | from unittest import TestCase 6 | 7 | from xrpl import XRPLException 8 | from xrpl.utils import parse_nftoken_id 9 | 10 | 11 | class TestParseNFTokenID(TestCase): 12 | """Test parse_nftoken_id.""" 13 | 14 | def test_parse_nftoken_id_successful(self) -> None: 15 | nft_id = "000B0539C35B55AA096BA6D87A6E6C965A6534150DC56E5E12C5D09E0000000C" 16 | result = parse_nftoken_id(nft_id) 17 | expected = { 18 | "nftoken_id": nft_id, 19 | "flags": 11, 20 | "transfer_fee": 1337, 21 | "issuer": "rJoxBSzpXhPtAuqFmqxQtGKjA13jUJWthE", 22 | "taxon": 1337, 23 | "sequence": 12, 24 | } 25 | self.assertEqual(result, expected) 26 | 27 | def test_parse_nftoken_id_raises(self) -> None: 28 | with self.assertRaises(XRPLException): 29 | parse_nftoken_id("ABCD") 30 | -------------------------------------------------------------------------------- /tests/unit/utils/test_str_conversions.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | import xrpl.utils 4 | 5 | _ORIGINAL = "https://en.wikipedia.org/wiki/Sunn_O%29%29%29" 6 | _HEX = """\ 7 | 68747470733a2f2f656e2e77696b6970656469612e6f72672f7769\ 8 | 6b692f53756e6e5f4f253239253239253239\ 9 | """ 10 | 11 | 12 | class TestStrConversions(TestCase): 13 | def test_str_to_hex(self): 14 | self.assertTrue(xrpl.utils.str_to_hex(_ORIGINAL) == _HEX) 15 | 16 | def test_hex_to_str(self): 17 | self.assertTrue(xrpl.utils.hex_to_str(_HEX) == _ORIGINAL) 18 | -------------------------------------------------------------------------------- /tests/unit/utils/txn_parser/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/unit/utils/txn_parser/__init__.py -------------------------------------------------------------------------------- /tests/unit/wallet/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/tests/unit/wallet/__init__.py -------------------------------------------------------------------------------- /xrpl/__init__.py: -------------------------------------------------------------------------------- 1 | """High-level XRPL exports.""" 2 | 3 | from xrpl import account, clients, core, ledger, models, transaction, utils, wallet 4 | from xrpl.constants import CryptoAlgorithm, XRPLException 5 | 6 | __all__ = [ 7 | "CryptoAlgorithm", 8 | "XRPLException", 9 | "account", 10 | "clients", 11 | "core", 12 | "ledger", 13 | "models", 14 | "transaction", 15 | "utils", 16 | "wallet", 17 | ] 18 | -------------------------------------------------------------------------------- /xrpl/account/__init__.py: -------------------------------------------------------------------------------- 1 | """Methods for interacting with XRPL accounts.""" 2 | 3 | from xrpl.account.main import ( 4 | does_account_exist, 5 | get_account_root, 6 | get_balance, 7 | get_next_valid_seq_number, 8 | ) 9 | from xrpl.account.transaction_history import get_latest_transaction 10 | 11 | __all__ = [ 12 | "get_next_valid_seq_number", 13 | "get_balance", 14 | "get_account_root", 15 | "does_account_exist", 16 | "get_latest_transaction", 17 | ] 18 | -------------------------------------------------------------------------------- /xrpl/account/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/account/py.typed -------------------------------------------------------------------------------- /xrpl/account/transaction_history.py: -------------------------------------------------------------------------------- 1 | """High-level methods to obtain information about account transaction history.""" 2 | 3 | import asyncio 4 | 5 | from xrpl.asyncio.account import transaction_history 6 | from xrpl.clients.sync_client import SyncClient 7 | from xrpl.models.response import Response 8 | 9 | 10 | def get_latest_transaction(account: str, client: SyncClient) -> Response: 11 | """ 12 | Fetches the most recent transaction on the ledger associated with an account. 13 | 14 | Args: 15 | account: the account to query. 16 | client: the network client used to communicate with a rippled node. 17 | 18 | Returns: 19 | The Response object containing the transaction info. 20 | 21 | Raises: 22 | XRPLRequestFailureException: if the transaction fails. 23 | """ 24 | return asyncio.run(transaction_history.get_latest_transaction(account, client)) 25 | -------------------------------------------------------------------------------- /xrpl/asyncio/__init__.py: -------------------------------------------------------------------------------- 1 | """High-level XRPL exports for async support.""" 2 | 3 | from xrpl.asyncio import account, clients, ledger, transaction, wallet 4 | 5 | __all__ = ["account", "clients", "ledger", "transaction", "wallet"] 6 | -------------------------------------------------------------------------------- /xrpl/asyncio/account/__init__.py: -------------------------------------------------------------------------------- 1 | """Async methods for interacting with XRPL accounts.""" 2 | 3 | from xrpl.asyncio.account.main import ( 4 | does_account_exist, 5 | get_account_root, 6 | get_balance, 7 | get_next_valid_seq_number, 8 | ) 9 | from xrpl.asyncio.account.transaction_history import get_latest_transaction 10 | 11 | __all__ = [ 12 | "get_next_valid_seq_number", 13 | "get_balance", 14 | "get_account_root", 15 | "does_account_exist", 16 | "get_latest_transaction", 17 | ] 18 | -------------------------------------------------------------------------------- /xrpl/asyncio/account/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/asyncio/account/py.typed -------------------------------------------------------------------------------- /xrpl/asyncio/account/transaction_history.py: -------------------------------------------------------------------------------- 1 | """High-level methods to obtain information about account transaction history.""" 2 | 3 | from xrpl.asyncio.clients import Client, XRPLRequestFailureException 4 | from xrpl.core.addresscodec import is_valid_xaddress, xaddress_to_classic_address 5 | from xrpl.models.requests import AccountTx 6 | from xrpl.models.response import Response 7 | 8 | 9 | async def get_latest_transaction(account: str, client: Client) -> Response: 10 | """ 11 | Fetches the most recent transaction on the ledger associated with an account. 12 | 13 | Args: 14 | account: the account to query. 15 | client: the network client used to communicate with a rippled node. 16 | 17 | Returns: 18 | The Response object containing the transaction info. 19 | 20 | Raises: 21 | XRPLRequestFailureException: if the transaction fails. 22 | """ 23 | # max == -1 means that it's the most recent validated ledger version 24 | if is_valid_xaddress(account): 25 | account, _, _ = xaddress_to_classic_address(account) 26 | response = await client._request_impl( 27 | AccountTx(account=account, ledger_index_max=-1, limit=1) 28 | ) 29 | if not response.is_successful(): 30 | raise XRPLRequestFailureException(response.result) 31 | return response 32 | -------------------------------------------------------------------------------- /xrpl/asyncio/clients/__init__.py: -------------------------------------------------------------------------------- 1 | """Asynchronous network clients for interacting with the XRPL.""" 2 | 3 | from xrpl.asyncio.clients.async_json_rpc_client import AsyncJsonRpcClient 4 | from xrpl.asyncio.clients.async_websocket_client import AsyncWebsocketClient 5 | from xrpl.asyncio.clients.client import Client 6 | from xrpl.asyncio.clients.exceptions import XRPLRequestFailureException 7 | from xrpl.asyncio.clients.utils import ( 8 | json_to_response, 9 | request_to_json_rpc, 10 | request_to_websocket, 11 | websocket_to_response, 12 | ) 13 | 14 | __all__ = [ 15 | "AsyncJsonRpcClient", 16 | "AsyncWebsocketClient", 17 | "Client", 18 | "json_to_response", 19 | "request_to_json_rpc", 20 | "XRPLRequestFailureException", 21 | "request_to_websocket", 22 | "websocket_to_response", 23 | ] 24 | -------------------------------------------------------------------------------- /xrpl/asyncio/clients/async_client.py: -------------------------------------------------------------------------------- 1 | """Interface for all async network clients to follow.""" 2 | 3 | from __future__ import annotations 4 | 5 | from typing_extensions import Self 6 | 7 | from xrpl.asyncio.clients.client import Client 8 | from xrpl.models.requests.request import Request 9 | from xrpl.models.response import Response 10 | 11 | 12 | class AsyncClient(Client): 13 | """ 14 | Interface for all async network clients to follow. 15 | 16 | :meta private: 17 | """ 18 | 19 | async def request(self: Self, request: Request) -> Response: 20 | """ 21 | Makes a request with this client and returns the response. 22 | 23 | Arguments: 24 | request: The Request to send. 25 | 26 | Returns: 27 | The Response for the given Request. 28 | """ 29 | return await self._request_impl(request) 30 | -------------------------------------------------------------------------------- /xrpl/asyncio/clients/async_json_rpc_client.py: -------------------------------------------------------------------------------- 1 | """An async client for interacting with the rippled JSON RPC.""" 2 | 3 | from xrpl.asyncio.clients.async_client import AsyncClient 4 | from xrpl.asyncio.clients.json_rpc_base import JsonRpcBase 5 | 6 | 7 | class AsyncJsonRpcClient(AsyncClient, JsonRpcBase): 8 | """An async client for interacting with the rippled JSON RPC.""" 9 | 10 | pass 11 | -------------------------------------------------------------------------------- /xrpl/asyncio/clients/exceptions.py: -------------------------------------------------------------------------------- 1 | """General XRPL Client Exceptions.""" 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Any, Dict 6 | 7 | from typing_extensions import Self 8 | 9 | from xrpl.constants import XRPLException 10 | 11 | 12 | class XRPLRequestFailureException(XRPLException): 13 | """XRPL Request Exception, when the request fails.""" 14 | 15 | def __init__(self: Self, result: Dict[str, Any]) -> None: 16 | """ 17 | Initializes a XRPLRequestFailureException. 18 | 19 | Args: 20 | result: the error result returned by the ledger. 21 | """ 22 | self.error = result["error"] 23 | self.error_message = None 24 | if "error_message" in result and result["error_message"] is not None: 25 | self.error_message = result["error_message"] 26 | elif "error_exception" in result: 27 | self.error_message = result["error_exception"] 28 | self.message = f"Request failed, {self.error}: {self.error_message}" 29 | super().__init__(self.message) 30 | 31 | 32 | class XRPLWebsocketException(XRPLException): 33 | """ 34 | XRPL Websocket Exception. Thrown when something goes wrong with the Web Socket 35 | client. 36 | """ 37 | 38 | pass 39 | -------------------------------------------------------------------------------- /xrpl/asyncio/clients/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/asyncio/clients/py.typed -------------------------------------------------------------------------------- /xrpl/asyncio/ledger/__init__.py: -------------------------------------------------------------------------------- 1 | """Async methods for obtaining information about the status of the XRP Ledger.""" 2 | 3 | from xrpl.asyncio.ledger.main import ( 4 | get_fee, 5 | get_latest_open_ledger_sequence, 6 | get_latest_validated_ledger_sequence, 7 | ) 8 | 9 | __all__ = [ 10 | "get_latest_validated_ledger_sequence", 11 | "get_fee", 12 | "get_latest_open_ledger_sequence", 13 | ] 14 | -------------------------------------------------------------------------------- /xrpl/asyncio/ledger/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/asyncio/ledger/py.typed -------------------------------------------------------------------------------- /xrpl/asyncio/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/asyncio/py.typed -------------------------------------------------------------------------------- /xrpl/asyncio/transaction/__init__.py: -------------------------------------------------------------------------------- 1 | """Async methods for working with transactions on the XRP Ledger.""" 2 | 3 | from xrpl.asyncio.transaction.main import ( 4 | _calculate_fee_per_transaction_type, 5 | autofill, 6 | autofill_and_sign, 7 | sign, 8 | sign_and_submit, 9 | simulate, 10 | submit, 11 | transaction_json_to_binary_codec_form, 12 | ) 13 | from xrpl.asyncio.transaction.reliable_submission import ( 14 | XRPLReliableSubmissionException, 15 | submit_and_wait, 16 | ) 17 | 18 | __all__ = [ 19 | "autofill", 20 | "autofill_and_sign", 21 | "sign", 22 | "sign_and_submit", 23 | "simulate", 24 | "submit", 25 | "submit_and_wait", 26 | "transaction_json_to_binary_codec_form", 27 | "XRPLReliableSubmissionException", 28 | "_calculate_fee_per_transaction_type", 29 | ] 30 | -------------------------------------------------------------------------------- /xrpl/asyncio/transaction/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/asyncio/transaction/py.typed -------------------------------------------------------------------------------- /xrpl/asyncio/wallet/__init__.py: -------------------------------------------------------------------------------- 1 | """Async methods for working with XRPL wallets.""" 2 | 3 | from xrpl.asyncio.wallet.wallet_generation import ( 4 | XRPLFaucetException, 5 | generate_faucet_wallet, 6 | ) 7 | 8 | __all__ = ["XRPLFaucetException", "generate_faucet_wallet"] 9 | -------------------------------------------------------------------------------- /xrpl/asyncio/wallet/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/asyncio/wallet/py.typed -------------------------------------------------------------------------------- /xrpl/clients/__init__.py: -------------------------------------------------------------------------------- 1 | """Synchronous network clients for interacting with the XRPL.""" 2 | 3 | from xrpl.asyncio.clients.client import Client 4 | from xrpl.asyncio.clients.exceptions import XRPLRequestFailureException 5 | from xrpl.asyncio.clients.utils import ( 6 | json_to_response, 7 | request_to_json_rpc, 8 | request_to_websocket, 9 | websocket_to_response, 10 | ) 11 | from xrpl.clients.json_rpc_client import JsonRpcClient 12 | from xrpl.clients.websocket_client import WebsocketClient 13 | 14 | __all__ = [ 15 | "Client", 16 | "JsonRpcClient", 17 | "request_to_json_rpc", 18 | "json_to_response", 19 | "request_to_websocket", 20 | "XRPLRequestFailureException", 21 | "websocket_to_response", 22 | "WebsocketClient", 23 | ] 24 | -------------------------------------------------------------------------------- /xrpl/clients/json_rpc_client.py: -------------------------------------------------------------------------------- 1 | """A sync client for interacting with the rippled JSON RPC.""" 2 | 3 | from xrpl.asyncio.clients.json_rpc_base import JsonRpcBase 4 | from xrpl.clients.sync_client import SyncClient 5 | 6 | 7 | class JsonRpcClient(SyncClient, JsonRpcBase): 8 | """A sync client for interacting with the rippled JSON RPC.""" 9 | 10 | pass 11 | -------------------------------------------------------------------------------- /xrpl/clients/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/clients/py.typed -------------------------------------------------------------------------------- /xrpl/clients/sync_client.py: -------------------------------------------------------------------------------- 1 | """Interface for all sync network clients to follow.""" 2 | 3 | from __future__ import annotations 4 | 5 | import asyncio 6 | 7 | from typing_extensions import Self 8 | 9 | from xrpl.asyncio.clients.client import Client 10 | from xrpl.models.requests.request import Request 11 | from xrpl.models.response import Response 12 | 13 | 14 | class SyncClient(Client): 15 | """ 16 | Interface for all sync network clients to follow. 17 | 18 | :meta private: 19 | """ 20 | 21 | def request(self: Self, request: Request) -> Response: 22 | """ 23 | Makes a request with this client and returns the response. 24 | 25 | Arguments: 26 | request: The Request to send. 27 | 28 | Returns: 29 | The Response for the given Request. 30 | """ 31 | return asyncio.run(self._request_impl(request)) 32 | -------------------------------------------------------------------------------- /xrpl/core/__init__.py: -------------------------------------------------------------------------------- 1 | """Core codec functions for interacting with the XRPL.""" 2 | 3 | from xrpl.core import addresscodec, binarycodec, keypairs 4 | 5 | __all__ = ["addresscodec", "binarycodec", "keypairs"] 6 | -------------------------------------------------------------------------------- /xrpl/core/addresscodec/__init__.py: -------------------------------------------------------------------------------- 1 | """Functions for encoding and decoding XRP Ledger addresses and seeds.""" 2 | 3 | from xrpl.core.addresscodec.codec import ( 4 | SEED_LENGTH, 5 | decode_account_public_key, 6 | decode_classic_address, 7 | decode_node_public_key, 8 | decode_seed, 9 | encode_account_public_key, 10 | encode_classic_address, 11 | encode_node_public_key, 12 | encode_seed, 13 | is_valid_classic_address, 14 | ) 15 | from xrpl.core.addresscodec.exceptions import XRPLAddressCodecException 16 | from xrpl.core.addresscodec.main import ( 17 | classic_address_to_xaddress, 18 | ensure_classic_address, 19 | is_valid_xaddress, 20 | xaddress_to_classic_address, 21 | ) 22 | from xrpl.core.addresscodec.utils import XRPL_ALPHABET 23 | 24 | __all__ = [ 25 | "classic_address_to_xaddress", 26 | "decode_account_public_key", 27 | "decode_classic_address", 28 | "decode_node_public_key", 29 | "decode_seed", 30 | "encode_seed", 31 | "encode_account_public_key", 32 | "encode_classic_address", 33 | "encode_node_public_key", 34 | "ensure_classic_address", 35 | "is_valid_classic_address", 36 | "is_valid_xaddress", 37 | "SEED_LENGTH", 38 | "xaddress_to_classic_address", 39 | "XRPLAddressCodecException", 40 | "XRPL_ALPHABET", 41 | ] 42 | -------------------------------------------------------------------------------- /xrpl/core/addresscodec/exceptions.py: -------------------------------------------------------------------------------- 1 | """General XRPL Address Codec Exceptions.""" 2 | 3 | from xrpl.constants import XRPLException 4 | 5 | 6 | class XRPLAddressCodecException(XRPLException): 7 | """General XRPL Address Codec Exception.""" 8 | 9 | pass 10 | -------------------------------------------------------------------------------- /xrpl/core/addresscodec/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/core/addresscodec/py.typed -------------------------------------------------------------------------------- /xrpl/core/addresscodec/utils.py: -------------------------------------------------------------------------------- 1 | """This module contains commonly-used constants.""" 2 | 3 | from typing_extensions import Final 4 | 5 | # The dictionary used for XRPL base58 encodings 6 | XRPL_ALPHABET: Final[bytes] = ( 7 | b"rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz" 8 | ) 9 | -------------------------------------------------------------------------------- /xrpl/core/binarycodec/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Functions for encoding objects into the XRP Ledger's canonical 3 | binary format and decoding them. 4 | """ 5 | 6 | from xrpl.core.binarycodec.exceptions import XRPLBinaryCodecException 7 | from xrpl.core.binarycodec.main import ( 8 | decode, 9 | encode, 10 | encode_for_multisigning, 11 | encode_for_signing, 12 | encode_for_signing_batch, 13 | encode_for_signing_claim, 14 | ) 15 | 16 | __all__ = [ 17 | "decode", 18 | "encode", 19 | "encode_for_signing_batch", 20 | "encode_for_multisigning", 21 | "encode_for_signing", 22 | "encode_for_signing_claim", 23 | "XRPLBinaryCodecException", 24 | ] 25 | -------------------------------------------------------------------------------- /xrpl/core/binarycodec/binary_wrappers/__init__.py: -------------------------------------------------------------------------------- 1 | """Wrapper classes around byte buffers used for serialization and deserialization.""" 2 | 3 | from xrpl.core.binarycodec.binary_wrappers.binary_parser import BinaryParser 4 | from xrpl.core.binarycodec.binary_wrappers.binary_serializer import BinarySerializer 5 | 6 | __all__ = ["BinaryParser", "BinarySerializer"] 7 | -------------------------------------------------------------------------------- /xrpl/core/binarycodec/definitions/__init__.py: -------------------------------------------------------------------------------- 1 | """Handles the XRPL type and definition specifics.""" 2 | 3 | from xrpl.core.binarycodec.definitions.definitions import ( 4 | get_field_header_from_name, 5 | get_field_instance, 6 | get_field_name_from_header, 7 | get_ledger_entry_type_code, 8 | get_ledger_entry_type_name, 9 | get_permission_value_type_code, 10 | get_permission_value_type_name, 11 | get_transaction_result_code, 12 | get_transaction_result_name, 13 | get_transaction_type_code, 14 | get_transaction_type_name, 15 | load_definitions, 16 | ) 17 | from xrpl.core.binarycodec.definitions.field_header import FieldHeader 18 | from xrpl.core.binarycodec.definitions.field_info import FieldInfo 19 | from xrpl.core.binarycodec.definitions.field_instance import FieldInstance 20 | 21 | __all__ = [ 22 | "FieldHeader", 23 | "FieldInfo", 24 | "FieldInstance", 25 | "load_definitions", 26 | "get_field_header_from_name", 27 | "get_field_name_from_header", 28 | "get_field_instance", 29 | "get_ledger_entry_type_code", 30 | "get_ledger_entry_type_name", 31 | "get_transaction_result_code", 32 | "get_transaction_result_name", 33 | "get_transaction_type_code", 34 | "get_transaction_type_name", 35 | "get_permission_value_type_code", 36 | "get_permission_value_type_name", 37 | ] 38 | -------------------------------------------------------------------------------- /xrpl/core/binarycodec/definitions/field_info.py: -------------------------------------------------------------------------------- 1 | """Model object for field info from the "fields" section of definitions.json.""" 2 | 3 | from __future__ import annotations # Requires Python 3.7+ 4 | 5 | from typing_extensions import Self 6 | 7 | 8 | class FieldInfo: 9 | """Model object for field info metadata from the "fields" section of 10 | definitions.json. 11 | """ 12 | 13 | def __init__( 14 | self: Self, 15 | nth: int, 16 | is_variable_length_encoded: bool, 17 | is_serialized: bool, 18 | is_signing_field: bool, 19 | type_name: str, 20 | ) -> None: 21 | """ 22 | :param nth: The field code -- sort order position for fields of the same type. 23 | :param is_variable_length_encoded: Whether the serialized length of this field 24 | varies. 25 | :param is_serialized: If the field is presented in binary serialized 26 | representation. 27 | :param is_signing_field: If the field should be included in signed transactions. 28 | :param type_name: The name of this field's serialization type, 29 | e.g. UInt32, AccountID, etc. 30 | """ 31 | self.nth = nth 32 | self.is_variable_length_encoded = is_variable_length_encoded 33 | self.is_serialized = is_serialized 34 | self.is_signing_field = is_signing_field 35 | self.type = type_name 36 | -------------------------------------------------------------------------------- /xrpl/core/binarycodec/exceptions.py: -------------------------------------------------------------------------------- 1 | """General XRPL Binary Codec Exceptions.""" 2 | 3 | from xrpl.constants import XRPLException 4 | 5 | 6 | class XRPLBinaryCodecException(XRPLException): 7 | """General XRPL Binary Codec Exception.""" 8 | 9 | pass 10 | -------------------------------------------------------------------------------- /xrpl/core/binarycodec/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/core/binarycodec/py.typed -------------------------------------------------------------------------------- /xrpl/core/binarycodec/types/__init__.py: -------------------------------------------------------------------------------- 1 | """Top-level exports for types used in binary_codec.""" 2 | 3 | from xrpl.core.binarycodec.types.account_id import AccountID 4 | from xrpl.core.binarycodec.types.amount import Amount 5 | from xrpl.core.binarycodec.types.blob import Blob 6 | from xrpl.core.binarycodec.types.currency import Currency 7 | from xrpl.core.binarycodec.types.hash import Hash 8 | from xrpl.core.binarycodec.types.hash128 import Hash128 9 | from xrpl.core.binarycodec.types.hash160 import Hash160 10 | from xrpl.core.binarycodec.types.hash192 import Hash192 11 | from xrpl.core.binarycodec.types.hash256 import Hash256 12 | from xrpl.core.binarycodec.types.issue import Issue 13 | from xrpl.core.binarycodec.types.path_set import PathSet 14 | from xrpl.core.binarycodec.types.st_array import STArray 15 | from xrpl.core.binarycodec.types.st_object import STObject 16 | from xrpl.core.binarycodec.types.uint import UInt 17 | from xrpl.core.binarycodec.types.uint8 import UInt8 18 | from xrpl.core.binarycodec.types.uint16 import UInt16 19 | from xrpl.core.binarycodec.types.uint32 import UInt32 20 | from xrpl.core.binarycodec.types.uint64 import UInt64 21 | from xrpl.core.binarycodec.types.vector256 import Vector256 22 | from xrpl.core.binarycodec.types.xchain_bridge import XChainBridge 23 | 24 | __all__ = [ 25 | "AccountID", 26 | "Amount", 27 | "Blob", 28 | "Currency", 29 | "Hash", 30 | "Hash128", 31 | "Hash160", 32 | "Hash192", 33 | "Hash256", 34 | "Issue", 35 | "PathSet", 36 | "STObject", 37 | "STArray", 38 | "UInt", 39 | "UInt8", 40 | "UInt16", 41 | "UInt32", 42 | "UInt64", 43 | "Vector256", 44 | "XChainBridge", 45 | ] 46 | -------------------------------------------------------------------------------- /xrpl/core/binarycodec/types/hash128.py: -------------------------------------------------------------------------------- 1 | """ 2 | Codec for serializing and deserializing a hash field with a width 3 | of 128 bits (16 bytes). 4 | `See Hash Fields `_ 5 | """ 6 | 7 | from __future__ import annotations 8 | 9 | from typing import Optional, Type 10 | 11 | from typing_extensions import Self 12 | 13 | from xrpl.core.binarycodec.exceptions import XRPLBinaryCodecException 14 | from xrpl.core.binarycodec.types.hash import Hash 15 | 16 | 17 | class Hash128(Hash): 18 | """ 19 | Codec for serializing and deserializing a hash field with a width 20 | of 128 bits (16 bytes). 21 | `See Hash Fields `_ 22 | """ 23 | 24 | def __init__(self: Self, buffer: Optional[bytes]) -> None: 25 | """ 26 | Construct a Hash128. 27 | 28 | Args: 29 | buffer: The byte buffer that will be used to store the serialized 30 | encoding of this field. 31 | """ 32 | buffer = ( 33 | buffer 34 | if buffer is not None and len(buffer) > 0 35 | else bytes(self._get_length()) 36 | ) 37 | 38 | if len(buffer) != self._get_length(): 39 | raise XRPLBinaryCodecException( 40 | f"Invalid hash length {len(buffer)}. Expected {self._get_length()}" 41 | ) 42 | super().__init__(buffer) 43 | 44 | def __str__(self: Self) -> str: 45 | """Returns a hex-encoded string representation of the bytes buffer.""" 46 | hex = self.to_hex() 47 | if hex == "0" * len(hex): 48 | return "" 49 | return hex 50 | 51 | @classmethod 52 | def _get_length(cls: Type[Self]) -> int: 53 | return 16 54 | -------------------------------------------------------------------------------- /xrpl/core/binarycodec/types/hash160.py: -------------------------------------------------------------------------------- 1 | """Codec for serializing and deserializing a hash field with a width 2 | of 160 bits (20 bytes). 3 | `See Hash Fields `_ 4 | """ 5 | 6 | from __future__ import annotations 7 | 8 | from typing import Type 9 | 10 | from typing_extensions import Self 11 | 12 | from xrpl.core.binarycodec.types.hash import Hash 13 | 14 | 15 | class Hash160(Hash): 16 | """ 17 | Codec for serializing and deserializing a hash field with a width 18 | of 160 bits (20 bytes). 19 | `See Hash Fields `_ 20 | """ 21 | 22 | @classmethod 23 | def _get_length(cls: Type[Self]) -> int: 24 | return 20 25 | -------------------------------------------------------------------------------- /xrpl/core/binarycodec/types/hash192.py: -------------------------------------------------------------------------------- 1 | """Codec for serializing and deserializing a hash field with a width 2 | of 192 bits (24 bytes). 3 | `See Hash Fields `_ 4 | """ 5 | 6 | from __future__ import annotations 7 | 8 | from typing import Type 9 | 10 | from typing_extensions import Self 11 | 12 | from xrpl.core.binarycodec.types.hash import Hash 13 | 14 | HASH192_BYTES = 24 15 | 16 | 17 | class Hash192(Hash): 18 | """ 19 | Codec for serializing and deserializing a hash field with a width 20 | of 192 bits (24 bytes). 21 | `See Hash Fields `_ 22 | """ 23 | 24 | @classmethod 25 | def _get_length(cls: Type[Self]) -> int: 26 | return 24 27 | -------------------------------------------------------------------------------- /xrpl/core/binarycodec/types/hash256.py: -------------------------------------------------------------------------------- 1 | """ 2 | Codec for serializing and deserializing a hash field with a width 3 | of 256 bits (32 bytes). 4 | `See Hash Fields `_ 5 | """ 6 | 7 | from __future__ import annotations 8 | 9 | from typing import Type 10 | 11 | from typing_extensions import Self 12 | 13 | from xrpl.core.binarycodec.types.hash import Hash 14 | 15 | 16 | class Hash256(Hash): 17 | """ 18 | Codec for serializing and deserializing a hash field with a width 19 | of 256 bits (32 bytes). 20 | `See Hash Fields `_ 21 | """ 22 | 23 | @classmethod 24 | def _get_length(cls: Type[Self]) -> int: 25 | return 32 26 | -------------------------------------------------------------------------------- /xrpl/core/keypairs/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Low-level functions for creating and using cryptographic keys with the XRP 3 | Ledger. 4 | """ 5 | 6 | from xrpl.core.keypairs.exceptions import XRPLKeypairsException 7 | from xrpl.core.keypairs.main import ( 8 | derive_classic_address, 9 | derive_keypair, 10 | generate_seed, 11 | is_valid_message, 12 | sign, 13 | ) 14 | 15 | __all__ = [ 16 | "derive_classic_address", 17 | "derive_keypair", 18 | "generate_seed", 19 | "is_valid_message", 20 | "sign", 21 | "XRPLKeypairsException", 22 | ] 23 | -------------------------------------------------------------------------------- /xrpl/core/keypairs/crypto_implementation.py: -------------------------------------------------------------------------------- 1 | """ 2 | Abstract base class for cryptographic algorithms in the XRP Ledger. The classes 3 | for all cryptographic algorithms are derived from this interface. 4 | """ 5 | 6 | from __future__ import annotations 7 | 8 | from abc import ABC, abstractmethod 9 | from typing import Tuple, Type 10 | 11 | from ecpy.keys import ECPrivateKey # type: ignore 12 | from typing_extensions import Self 13 | 14 | 15 | class CryptoImplementation(ABC): 16 | """ 17 | Abstract base class for cryptographic algorithms in the XRP Ledger. The 18 | classes for all cryptographic algorithms are derived from this interface. 19 | """ 20 | 21 | @classmethod 22 | @abstractmethod 23 | def derive_keypair( # noqa: D102 24 | cls: Type[Self], 25 | decoded_seed: bytes, 26 | is_validator: bool, 27 | ) -> Tuple[str, str]: 28 | pass 29 | 30 | @classmethod 31 | @abstractmethod 32 | def sign( # noqa: D102 33 | cls: Type[Self], 34 | message: bytes, 35 | private_key: str, 36 | ) -> bytes: 37 | pass 38 | 39 | @classmethod 40 | @abstractmethod 41 | def is_valid_message( # noqa: D102 42 | cls: Type[Self], 43 | message: bytes, 44 | signature: bytes, 45 | public_key: str, 46 | ) -> bool: 47 | pass 48 | 49 | @classmethod 50 | def _private_key_to_str(cls: Type[Self], key: ECPrivateKey) -> str: 51 | return format(key.d, "x") 52 | -------------------------------------------------------------------------------- /xrpl/core/keypairs/exceptions.py: -------------------------------------------------------------------------------- 1 | """XRPL keypair codec exceptions.""" 2 | 3 | from xrpl.constants import XRPLException 4 | 5 | 6 | class XRPLKeypairsException(XRPLException): 7 | """General XRPL Keypair Codec Exception.""" 8 | 9 | pass 10 | -------------------------------------------------------------------------------- /xrpl/core/keypairs/helpers.py: -------------------------------------------------------------------------------- 1 | """Miscellaneous functions that are private to xrpl.core.keypairs.""" 2 | 3 | import hashlib 4 | 5 | import Crypto.Hash.RIPEMD160 as RIPEMD160 6 | 7 | 8 | def sha512_first_half(message: bytes) -> bytes: 9 | """ 10 | Returns the first 32 bytes of SHA-512 hash of message. 11 | 12 | Args: 13 | message: Bytes input to hash. 14 | 15 | Returns: 16 | The first 32 bytes of SHA-512 hash of message. 17 | """ 18 | return hashlib.sha512(message).digest()[:32] 19 | 20 | 21 | def get_account_id(public_key: bytes) -> bytes: 22 | """ 23 | Returns the account ID for a given public key. See 24 | https://xrpl.org/cryptographic-keys.html#account-id-and-address 25 | to learn about the relationship between keys and account IDs. 26 | 27 | Args: 28 | public_key: Unencoded public key. 29 | 30 | Returns: 31 | The account ID for the given public key. 32 | """ 33 | sha_hash = hashlib.sha256(public_key).digest() 34 | return bytes(RIPEMD160.new(sha_hash).digest()) 35 | -------------------------------------------------------------------------------- /xrpl/core/keypairs/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/core/keypairs/py.typed -------------------------------------------------------------------------------- /xrpl/core/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/core/py.typed -------------------------------------------------------------------------------- /xrpl/ledger/__init__.py: -------------------------------------------------------------------------------- 1 | """Methods for obtaining information about the status of the XRP Ledger.""" 2 | 3 | from xrpl.ledger.main import ( 4 | get_fee, 5 | get_latest_open_ledger_sequence, 6 | get_latest_validated_ledger_sequence, 7 | ) 8 | 9 | __all__ = [ 10 | "get_latest_validated_ledger_sequence", 11 | "get_fee", 12 | "get_latest_open_ledger_sequence", 13 | ] 14 | -------------------------------------------------------------------------------- /xrpl/ledger/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/ledger/py.typed -------------------------------------------------------------------------------- /xrpl/models/__init__.py: -------------------------------------------------------------------------------- 1 | """Top-level exports for the models package.""" 2 | 3 | from xrpl.models import amounts, currencies, requests, transactions 4 | from xrpl.models.amounts import * # noqa: F401, F403 5 | from xrpl.models.auth_account import AuthAccount 6 | from xrpl.models.currencies import * # noqa: F401, F403 7 | from xrpl.models.exceptions import XRPLModelException 8 | from xrpl.models.path import Path, PathStep 9 | from xrpl.models.requests import * # noqa: F401, F403 10 | from xrpl.models.response import Response 11 | from xrpl.models.transactions import * # noqa: F401, F403 12 | from xrpl.models.transactions.pseudo_transactions import * # noqa: F401, F403 13 | from xrpl.models.xchain_bridge import XChainBridge 14 | 15 | __all__ = [ 16 | "XRPLModelException", 17 | "amounts", 18 | *amounts.__all__, 19 | "AuthAccount", 20 | "currencies", 21 | *currencies.__all__, 22 | "requests", 23 | *requests.__all__, 24 | "transactions", 25 | *transactions.__all__, 26 | *transactions.pseudo_transactions.__all__, 27 | "Path", 28 | "PathStep", 29 | "Response", 30 | "XChainBridge", 31 | ] 32 | -------------------------------------------------------------------------------- /xrpl/models/amounts/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | An Amount is an object specifying a currency, a quantity 3 | of that currency, and the counterparty (issuer) on the trustline 4 | that holds the value. For XRP, there is no counterparty. 5 | """ 6 | 7 | from xrpl.models.amounts.amount import ( 8 | Amount, 9 | get_amount_value, 10 | is_issued_currency, 11 | is_mpt, 12 | is_xrp, 13 | ) 14 | from xrpl.models.amounts.issued_currency_amount import IssuedCurrencyAmount 15 | from xrpl.models.amounts.mpt_amount import MPTAmount 16 | 17 | __all__ = [ 18 | "Amount", 19 | "IssuedCurrencyAmount", 20 | "is_xrp", 21 | "is_issued_currency", 22 | "is_mpt", 23 | "get_amount_value", 24 | "MPTAmount", 25 | ] 26 | -------------------------------------------------------------------------------- /xrpl/models/amounts/issued_currency_amount.py: -------------------------------------------------------------------------------- 1 | """ 2 | Specifies an amount in an issued currency. 3 | 4 | See https://xrpl.org/currency-formats.html#issued-currency-amounts. 5 | """ 6 | 7 | from __future__ import annotations 8 | 9 | from dataclasses import dataclass 10 | from typing import Dict, Union 11 | 12 | from typing_extensions import Self 13 | 14 | from xrpl.models.currencies import IssuedCurrency 15 | from xrpl.models.required import REQUIRED 16 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 17 | 18 | 19 | @require_kwargs_on_init 20 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 21 | class IssuedCurrencyAmount(IssuedCurrency): 22 | """ 23 | Specifies an amount in an issued currency. 24 | 25 | See https://xrpl.org/currency-formats.html#issued-currency-amounts. 26 | """ 27 | 28 | value: Union[str, int, float] = REQUIRED # type: ignore 29 | """ 30 | This field is required. 31 | 32 | :meta hide-value: 33 | """ 34 | 35 | def to_currency(self: Self) -> IssuedCurrency: 36 | """ 37 | Build an IssuedCurrency from this IssuedCurrencyAmount. 38 | 39 | Returns: 40 | The IssuedCurrency for this IssuedCurrencyAmount. 41 | """ 42 | return IssuedCurrency(issuer=self.issuer, currency=self.currency) 43 | 44 | def to_dict(self: Self) -> Dict[str, str]: 45 | """ 46 | Returns the dictionary representation of an IssuedCurrencyAmount. 47 | 48 | Returns: 49 | The dictionary representation of an IssuedCurrencyAmount. 50 | """ 51 | return {**super().to_dict(), "value": str(self.value)} 52 | -------------------------------------------------------------------------------- /xrpl/models/amounts/mpt_amount.py: -------------------------------------------------------------------------------- 1 | """Specifies an MPT amount.""" 2 | 3 | from __future__ import annotations 4 | 5 | from dataclasses import dataclass 6 | from typing import Dict 7 | 8 | from typing_extensions import Self 9 | 10 | from xrpl.models.base_model import BaseModel 11 | from xrpl.models.currencies.mpt_currency import MPTCurrency 12 | from xrpl.models.required import REQUIRED 13 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 14 | 15 | 16 | @require_kwargs_on_init 17 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 18 | class MPTAmount(BaseModel): 19 | """Specifies an MPT amount.""" 20 | 21 | mpt_issuance_id: str = REQUIRED # type: ignore 22 | """ 23 | This field is required. 24 | 25 | :meta hide-value: 26 | """ 27 | 28 | value: str = REQUIRED # type: ignore 29 | """ 30 | This field is required. 31 | 32 | :meta hide-value: 33 | """ 34 | 35 | def to_dict(self: Self) -> Dict[str, str]: 36 | """ 37 | Returns the dictionary representation of an MPTAmount. 38 | 39 | Returns: 40 | The dictionary representation of an MPTAmount. 41 | """ 42 | return {**super().to_dict(), "value": str(self.value)} 43 | 44 | def to_currency(self: Self) -> MPTCurrency: 45 | """ 46 | Build an MPTCurrency from this MPTAmount. 47 | 48 | Returns: 49 | The MPTCurrency for this MPTAmount. 50 | """ 51 | return MPTCurrency(mpt_issuance_id=self.mpt_issuance_id) 52 | -------------------------------------------------------------------------------- /xrpl/models/amounts/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/models/amounts/py.typed -------------------------------------------------------------------------------- /xrpl/models/auth_account.py: -------------------------------------------------------------------------------- 1 | """Model used in AMMBid transaction.""" 2 | 3 | from __future__ import annotations 4 | 5 | from dataclasses import dataclass 6 | 7 | from xrpl.models.nested_model import NestedModel 8 | from xrpl.models.required import REQUIRED 9 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 10 | 11 | 12 | @require_kwargs_on_init 13 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 14 | class AuthAccount(NestedModel): 15 | """Represents one entry in a list of AuthAccounts used in AMMBid transaction.""" 16 | 17 | account: str = REQUIRED # type: ignore 18 | """ 19 | This field is required. 20 | 21 | :meta hide-value: 22 | """ 23 | -------------------------------------------------------------------------------- /xrpl/models/currencies/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The XRP Ledger has three kinds of money: XRP, issued currencies, and MPTs. All types 3 | have high precision, although their formats are different. 4 | """ 5 | 6 | from xrpl.models.currencies.currency import Currency 7 | from xrpl.models.currencies.issued_currency import IssuedCurrency 8 | from xrpl.models.currencies.mpt_currency import MPTCurrency 9 | from xrpl.models.currencies.xrp import XRP 10 | 11 | __all__ = [ 12 | "Currency", 13 | "IssuedCurrency", 14 | "MPTCurrency", 15 | "XRP", 16 | ] 17 | -------------------------------------------------------------------------------- /xrpl/models/currencies/currency.py: -------------------------------------------------------------------------------- 1 | """ 2 | The XRP Ledger has two kinds of money: XRP, and issued 3 | currencies. Both types have high precision, although their 4 | formats are different. 5 | """ 6 | 7 | from typing import Union 8 | 9 | from xrpl.models.currencies.issued_currency import IssuedCurrency 10 | from xrpl.models.currencies.mpt_currency import MPTCurrency 11 | from xrpl.models.currencies.xrp import XRP 12 | 13 | Currency = Union[IssuedCurrency, MPTCurrency, XRP] 14 | -------------------------------------------------------------------------------- /xrpl/models/currencies/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/models/currencies/py.typed -------------------------------------------------------------------------------- /xrpl/models/exceptions.py: -------------------------------------------------------------------------------- 1 | """General XRPL Model Exceptions.""" 2 | 3 | from xrpl.constants import XRPLException 4 | 5 | 6 | class XRPLModelException(XRPLException): 7 | """General XRPL Model Exception.""" 8 | 9 | pass 10 | -------------------------------------------------------------------------------- /xrpl/models/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/models/py.typed -------------------------------------------------------------------------------- /xrpl/models/requests/account_currencies.py: -------------------------------------------------------------------------------- 1 | """ 2 | This request retrieves a list of currencies that an account can send or receive, 3 | based on its trust lines. 4 | 5 | This is not a thoroughly confirmed list, but it can be used to populate user 6 | interfaces. 7 | 8 | `See account_currencies `_ 9 | """ 10 | 11 | from dataclasses import dataclass, field 12 | 13 | from xrpl.models.requests.request import LookupByLedgerRequest, Request, RequestMethod 14 | from xrpl.models.required import REQUIRED 15 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 16 | 17 | 18 | @require_kwargs_on_init 19 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 20 | class AccountCurrencies(Request, LookupByLedgerRequest): 21 | """ 22 | This request retrieves a list of currencies that an account can send or receive, 23 | based on its trust lines. 24 | 25 | This is not a thoroughly confirmed list, but it can be used to populate user 26 | interfaces. 27 | 28 | `See account_currencies `_ 29 | """ 30 | 31 | account: str = REQUIRED # type: ignore 32 | """ 33 | This field is required. 34 | 35 | :meta hide-value: 36 | """ 37 | method: RequestMethod = field(default=RequestMethod.ACCOUNT_CURRENCIES, init=False) 38 | strict: bool = False 39 | -------------------------------------------------------------------------------- /xrpl/models/requests/account_info.py: -------------------------------------------------------------------------------- 1 | """ 2 | This request retrieves information about an account, its activity, and its XRP 3 | balance. 4 | 5 | All information retrieved is relative to a particular version of the ledger. 6 | 7 | `See account_info `_ 8 | """ 9 | 10 | from dataclasses import dataclass, field 11 | 12 | from xrpl.models.requests.request import LookupByLedgerRequest, Request, RequestMethod 13 | from xrpl.models.required import REQUIRED 14 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 15 | 16 | 17 | @require_kwargs_on_init 18 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 19 | class AccountInfo(Request, LookupByLedgerRequest): 20 | """ 21 | This request retrieves information about an account, its activity, and its XRP 22 | balance. 23 | 24 | All information retrieved is relative to a particular version of the ledger. 25 | 26 | `See account_info `_ 27 | """ 28 | 29 | account: str = REQUIRED # type: ignore 30 | """ 31 | This field is required. 32 | 33 | :meta hide-value: 34 | """ 35 | 36 | method: RequestMethod = field(default=RequestMethod.ACCOUNT_INFO, init=False) 37 | queue: bool = False 38 | signer_lists: bool = False 39 | strict: bool = False 40 | -------------------------------------------------------------------------------- /xrpl/models/requests/account_lines.py: -------------------------------------------------------------------------------- 1 | """ 2 | This request returns information about an account's trust lines, including balances 3 | in all non-XRP currencies and assets. All information retrieved is relative to a 4 | particular version of the ledger. 5 | 6 | `See account_lines `_ 7 | """ 8 | 9 | from dataclasses import dataclass, field 10 | from typing import Any, Optional 11 | 12 | from xrpl.models.requests.request import LookupByLedgerRequest, Request, RequestMethod 13 | from xrpl.models.required import REQUIRED 14 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 15 | 16 | 17 | @require_kwargs_on_init 18 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 19 | class AccountLines(Request, LookupByLedgerRequest): 20 | """ 21 | This request returns information about an account's trust lines, including balances 22 | in all non-XRP currencies and assets. All information retrieved is relative to a 23 | particular version of the ledger. 24 | 25 | `See account_lines `_ 26 | """ 27 | 28 | account: str = REQUIRED # type: ignore 29 | """ 30 | This field is required. 31 | 32 | :meta hide-value: 33 | """ 34 | 35 | method: RequestMethod = field(default=RequestMethod.ACCOUNT_LINES, init=False) 36 | peer: Optional[str] = None 37 | limit: Optional[int] = None 38 | # marker data shape is actually undefined in the spec, up to the 39 | # implementation of an individual server 40 | marker: Optional[Any] = None 41 | -------------------------------------------------------------------------------- /xrpl/models/requests/account_nfts.py: -------------------------------------------------------------------------------- 1 | """This method retrieves all of the NFTs currently owned by the specified account.""" 2 | 3 | from dataclasses import dataclass, field 4 | from typing import Any, Optional 5 | 6 | from xrpl.models.requests.request import LookupByLedgerRequest, Request, RequestMethod 7 | from xrpl.models.required import REQUIRED 8 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 9 | 10 | 11 | @require_kwargs_on_init 12 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 13 | class AccountNFTs(Request, LookupByLedgerRequest): 14 | """ 15 | This method retrieves all of the NFTs currently owned 16 | by the specified account. 17 | """ 18 | 19 | method: RequestMethod = field(default=RequestMethod.ACCOUNT_NFTS, init=False) 20 | account: str = REQUIRED # type: ignore 21 | """ 22 | The unique identifier of an account, typically the account's address. The 23 | request returns NFTs owned by this account. This value is required. 24 | 25 | :meta hide-value: 26 | """ 27 | 28 | limit: Optional[int] = None 29 | """Limit the number of NFTokens to retrieve.""" 30 | 31 | # marker data shape is actually undefined in the spec, up to the 32 | # implementation of an individual server 33 | marker: Optional[Any] = None 34 | """ 35 | Value from a previous paginated response. Resume retrieving data where 36 | that response left off. 37 | """ 38 | -------------------------------------------------------------------------------- /xrpl/models/requests/account_offers.py: -------------------------------------------------------------------------------- 1 | """ 2 | This request retrieves a list of offers made by a given account that are 3 | outstanding as of a particular ledger version. 4 | 5 | `See account_offers `_ 6 | """ 7 | 8 | from dataclasses import dataclass, field 9 | from typing import Any, Optional 10 | 11 | from xrpl.models.requests.request import LookupByLedgerRequest, Request, RequestMethod 12 | from xrpl.models.required import REQUIRED 13 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 14 | 15 | 16 | @require_kwargs_on_init 17 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 18 | class AccountOffers(Request, LookupByLedgerRequest): 19 | """ 20 | This request retrieves a list of offers made by a given account that are 21 | outstanding as of a particular ledger version. 22 | 23 | `See account_offers `_ 24 | """ 25 | 26 | account: str = REQUIRED # type: ignore 27 | """ 28 | This field is required. 29 | 30 | :meta hide-value: 31 | """ 32 | 33 | method: RequestMethod = field(default=RequestMethod.ACCOUNT_OFFERS, init=False) 34 | limit: Optional[int] = None 35 | # marker data shape is actually undefined in the spec, up to the 36 | # implementation of an individual server 37 | marker: Optional[Any] = None 38 | strict: bool = False 39 | -------------------------------------------------------------------------------- /xrpl/models/requests/account_tx.py: -------------------------------------------------------------------------------- 1 | """ 2 | This request retrieves from the ledger a list of transactions that involved the 3 | specified account. 4 | 5 | `See account_tx `_ 6 | """ 7 | 8 | from dataclasses import dataclass, field 9 | from typing import Any, Optional 10 | 11 | from xrpl.models.requests.request import LookupByLedgerRequest, Request, RequestMethod 12 | from xrpl.models.required import REQUIRED 13 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 14 | 15 | 16 | @require_kwargs_on_init 17 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 18 | class AccountTx(Request, LookupByLedgerRequest): 19 | """ 20 | This request retrieves from the ledger a list of transactions that involved the 21 | specified account. 22 | 23 | `See account_tx `_ 24 | """ 25 | 26 | account: str = REQUIRED # type: ignore 27 | """ 28 | This field is required. 29 | 30 | :meta hide-value: 31 | """ 32 | 33 | method: RequestMethod = field(default=RequestMethod.ACCOUNT_TX, init=False) 34 | ledger_index_min: Optional[int] = None 35 | ledger_index_max: Optional[int] = None 36 | binary: bool = False 37 | forward: bool = False 38 | limit: Optional[int] = None 39 | # marker data shape is actually undefined in the spec, up to the 40 | # implementation of an individual server 41 | marker: Optional[Any] = None 42 | -------------------------------------------------------------------------------- /xrpl/models/requests/amm_info.py: -------------------------------------------------------------------------------- 1 | """This request gets information about an Automated Market Maker (AMM) instance.""" 2 | 3 | from __future__ import annotations 4 | 5 | from dataclasses import dataclass, field 6 | from typing import Dict, Optional 7 | 8 | from typing_extensions import Self 9 | 10 | from xrpl.models.currencies import Currency 11 | from xrpl.models.requests.request import Request, RequestMethod 12 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 13 | 14 | 15 | @require_kwargs_on_init 16 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 17 | class AMMInfo(Request): 18 | """ 19 | The `amm_info` method gets information about an Automated Market Maker 20 | (AMM) instance. 21 | """ 22 | 23 | amm_account: Optional[str] = None 24 | """ 25 | The address of the AMM pool to look up. 26 | """ 27 | 28 | asset: Optional[Currency] = None 29 | """ 30 | One of the assets of the AMM pool to look up. 31 | """ 32 | 33 | asset2: Optional[Currency] = None 34 | """ 35 | The other asset of the AMM pool. 36 | """ 37 | 38 | method: RequestMethod = field(default=RequestMethod.AMM_INFO, init=False) 39 | 40 | def _get_errors(self: Self) -> Dict[str, str]: 41 | errors = super()._get_errors() 42 | if (self.asset is None) != (self.asset2 is None): 43 | errors["assets"] = "Must have both `asset` and `asset2` fields." 44 | if (self.asset is None) == (self.amm_account is None): 45 | errors["params"] = "Must not have both `asset` and `amm_account` fields." 46 | return errors 47 | -------------------------------------------------------------------------------- /xrpl/models/requests/book_offers.py: -------------------------------------------------------------------------------- 1 | """ 2 | The book_offers method retrieves a list of offers, also known 3 | as the order book, between two currencies. 4 | """ 5 | 6 | from dataclasses import dataclass, field 7 | from typing import Optional 8 | 9 | from xrpl.models.currencies import Currency 10 | from xrpl.models.requests.request import LookupByLedgerRequest, Request, RequestMethod 11 | from xrpl.models.required import REQUIRED 12 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 13 | 14 | 15 | @require_kwargs_on_init 16 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 17 | class BookOffers(Request, LookupByLedgerRequest): 18 | """ 19 | The book_offers method retrieves a list of offers, also known 20 | as the order book, between two currencies. 21 | """ 22 | 23 | taker_gets: Currency = REQUIRED # type: ignore 24 | """ 25 | This field is required. 26 | 27 | :meta hide-value: 28 | """ 29 | 30 | taker_pays: Currency = REQUIRED # type: ignore 31 | """ 32 | This field is required. 33 | 34 | :meta hide-value: 35 | """ 36 | 37 | method: RequestMethod = field(default=RequestMethod.BOOK_OFFERS, init=False) 38 | limit: Optional[int] = None 39 | taker: Optional[str] = None 40 | -------------------------------------------------------------------------------- /xrpl/models/requests/channel_verify.py: -------------------------------------------------------------------------------- 1 | """ 2 | The channel_verify method checks the validity of a 3 | signature that can be used to redeem a specific amount of 4 | XRP from a payment channel. 5 | """ 6 | 7 | from dataclasses import dataclass, field 8 | 9 | from xrpl.models.requests.request import Request, RequestMethod 10 | from xrpl.models.required import REQUIRED 11 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 12 | 13 | 14 | @require_kwargs_on_init 15 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 16 | class ChannelVerify(Request): 17 | """ 18 | The channel_verify method checks the validity of a 19 | signature that can be used to redeem a specific amount of 20 | XRP from a payment channel. 21 | """ 22 | 23 | method: RequestMethod = field(default=RequestMethod.CHANNEL_VERIFY, init=False) 24 | channel_id: str = REQUIRED # type: ignore 25 | """ 26 | This field is required. 27 | 28 | :meta hide-value: 29 | """ 30 | 31 | amount: str = REQUIRED # type: ignore 32 | """ 33 | This field is required. 34 | 35 | :meta hide-value: 36 | """ 37 | 38 | public_key: str = REQUIRED # type: ignore 39 | """ 40 | This field is required. 41 | 42 | :meta hide-value: 43 | """ 44 | 45 | signature: str = REQUIRED # type: ignore 46 | """ 47 | This field is required. 48 | 49 | :meta hide-value: 50 | """ 51 | -------------------------------------------------------------------------------- /xrpl/models/requests/deposit_authorized.py: -------------------------------------------------------------------------------- 1 | """ 2 | The deposit_authorized command indicates whether one account 3 | is authorized to send payments directly to another. See 4 | Deposit Authorization for information on how to require 5 | authorization to deliver money to your account. 6 | """ 7 | 8 | from dataclasses import dataclass, field 9 | from typing import List, Optional 10 | 11 | from xrpl.models.requests.request import LookupByLedgerRequest, Request, RequestMethod 12 | from xrpl.models.required import REQUIRED 13 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 14 | 15 | 16 | @require_kwargs_on_init 17 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 18 | class DepositAuthorized(Request, LookupByLedgerRequest): 19 | """ 20 | The deposit_authorized command indicates whether one account 21 | is authorized to send payments directly to another. See 22 | Deposit Authorization for information on how to require 23 | authorization to deliver money to your account. 24 | """ 25 | 26 | source_account: str = REQUIRED # type: ignore 27 | """ 28 | This field is required. 29 | 30 | :meta hide-value: 31 | """ 32 | 33 | destination_account: str = REQUIRED # type: ignore 34 | """ 35 | This field is required. 36 | 37 | :meta hide-value: 38 | """ 39 | 40 | method: RequestMethod = field(default=RequestMethod.DEPOSIT_AUTHORIZED, init=False) 41 | 42 | credentials: Optional[List[str]] = None 43 | """List of Credential ID strings. If this field is included, then the 44 | credential will be taken into account when analyzing whether the sender can send 45 | funds to the destination. 46 | """ 47 | -------------------------------------------------------------------------------- /xrpl/models/requests/feature.py: -------------------------------------------------------------------------------- 1 | """This request gets information about a network's amendments.""" 2 | 3 | from __future__ import annotations 4 | 5 | from dataclasses import dataclass, field 6 | from typing import Optional 7 | 8 | from xrpl.models.requests.request import Request, RequestMethod 9 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 10 | 11 | 12 | @require_kwargs_on_init 13 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 14 | class Feature(Request): 15 | """The `feature` method gets information about a network's amendments.""" 16 | 17 | feature: Optional[str] = None 18 | """ 19 | The hex-encoded feature hash. 20 | """ 21 | 22 | method: RequestMethod = field(default=RequestMethod.FEATURE, init=False) 23 | -------------------------------------------------------------------------------- /xrpl/models/requests/fee.py: -------------------------------------------------------------------------------- 1 | """ 2 | The fee command reports the current state of the open-ledger requirements 3 | for the transaction cost. This requires the FeeEscalation amendment to be 4 | enabled. 5 | 6 | This is a public command available to unprivileged users. 7 | """ 8 | 9 | from dataclasses import dataclass, field 10 | 11 | from xrpl.models.requests.request import Request, RequestMethod 12 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 13 | 14 | 15 | @require_kwargs_on_init 16 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 17 | class Fee(Request): 18 | """ 19 | The fee command reports the current state of the open-ledger requirements 20 | for the transaction cost. This requires the FeeEscalation amendment to be 21 | enabled. 22 | 23 | This is a public command available to unprivileged users. 24 | """ 25 | 26 | method: RequestMethod = field(default=RequestMethod.FEE, init=False) 27 | -------------------------------------------------------------------------------- /xrpl/models/requests/gateway_balances.py: -------------------------------------------------------------------------------- 1 | """ 2 | This request calculates the total balances issued by a given account, optionally 3 | excluding amounts held by operational addresses. 4 | 5 | `See gateway_balances `_ 6 | """ 7 | 8 | from dataclasses import dataclass, field 9 | from typing import List, Optional, Union 10 | 11 | from xrpl.models.requests.request import LookupByLedgerRequest, Request, RequestMethod 12 | from xrpl.models.required import REQUIRED 13 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 14 | 15 | 16 | @require_kwargs_on_init 17 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 18 | class GatewayBalances(Request, LookupByLedgerRequest): 19 | """ 20 | This request calculates the total balances issued by a given account, optionally 21 | excluding amounts held by operational addresses. 22 | 23 | `See gateway_balances `_ 24 | """ 25 | 26 | account: str = REQUIRED # type: ignore 27 | """ 28 | This field is required. 29 | 30 | :meta hide-value: 31 | """ 32 | 33 | method: RequestMethod = field(default=RequestMethod.GATEWAY_BALANCES, init=False) 34 | strict: bool = False 35 | hotwallet: Optional[Union[str, List[str]]] = None 36 | -------------------------------------------------------------------------------- /xrpl/models/requests/ledger.py: -------------------------------------------------------------------------------- 1 | """ 2 | Retrieve information about the public ledger. 3 | `See ledger `_ 4 | """ 5 | 6 | from dataclasses import dataclass, field 7 | 8 | from xrpl.models.requests.request import LookupByLedgerRequest, Request, RequestMethod 9 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 10 | 11 | 12 | @require_kwargs_on_init 13 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 14 | class Ledger(Request, LookupByLedgerRequest): 15 | """ 16 | Retrieve information about the public ledger. 17 | `See ledger `_ 18 | """ 19 | 20 | method: RequestMethod = field(default=RequestMethod.LEDGER, init=False) 21 | transactions: bool = False 22 | expand: bool = False 23 | owner_funds: bool = False 24 | binary: bool = False 25 | queue: bool = False 26 | -------------------------------------------------------------------------------- /xrpl/models/requests/ledger_closed.py: -------------------------------------------------------------------------------- 1 | """ 2 | The ledger_closed method returns the unique 3 | identifiers of the most recently closed ledger. 4 | (This ledger is not necessarily validated and 5 | immutable yet.) 6 | """ 7 | 8 | from dataclasses import dataclass, field 9 | 10 | from xrpl.models.requests.request import Request, RequestMethod 11 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 12 | 13 | 14 | @require_kwargs_on_init 15 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 16 | class LedgerClosed(Request): 17 | """ 18 | The ledger_closed method returns the unique 19 | identifiers of the most recently closed ledger. 20 | (This ledger is not necessarily validated and 21 | immutable yet.) 22 | """ 23 | 24 | method: RequestMethod = field(default=RequestMethod.LEDGER_CLOSED, init=False) 25 | -------------------------------------------------------------------------------- /xrpl/models/requests/ledger_current.py: -------------------------------------------------------------------------------- 1 | """ 2 | The ledger_current method returns the unique 3 | identifiers of the current in-progress ledger. 4 | This command is mostly useful for testing, 5 | because the ledger returned is still in flux. 6 | """ 7 | 8 | from dataclasses import dataclass, field 9 | 10 | from xrpl.models.requests.request import Request, RequestMethod 11 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 12 | 13 | 14 | @require_kwargs_on_init 15 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 16 | class LedgerCurrent(Request): 17 | """ 18 | The ledger_current method returns the unique 19 | identifiers of the current in-progress ledger. 20 | This command is mostly useful for testing, 21 | because the ledger returned is still in flux. 22 | """ 23 | 24 | method: RequestMethod = field(default=RequestMethod.LEDGER_CURRENT, init=False) 25 | -------------------------------------------------------------------------------- /xrpl/models/requests/ledger_data.py: -------------------------------------------------------------------------------- 1 | """ 2 | The ledger_data method retrieves contents of 3 | the specified ledger. You can iterate through 4 | several calls to retrieve the entire contents 5 | of a single ledger version. 6 | `See ledger data `_ 7 | """ 8 | 9 | from dataclasses import dataclass, field 10 | from typing import Any, Optional 11 | 12 | from xrpl.models.requests.ledger_entry import LedgerEntryType 13 | from xrpl.models.requests.request import LookupByLedgerRequest, Request, RequestMethod 14 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 15 | 16 | 17 | @require_kwargs_on_init 18 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 19 | class LedgerData(Request, LookupByLedgerRequest): 20 | """ 21 | The ledger_data method retrieves contents of 22 | the specified ledger. You can iterate through 23 | several calls to retrieve the entire contents 24 | of a single ledger version. 25 | `See ledger data `_ 26 | """ 27 | 28 | method: RequestMethod = field(default=RequestMethod.LEDGER_DATA, init=False) 29 | binary: bool = False 30 | limit: Optional[int] = None 31 | # marker data shape is actually undefined in the spec, up to the 32 | # implementation of an individual server 33 | marker: Optional[Any] = None 34 | type: Optional[LedgerEntryType] = None 35 | -------------------------------------------------------------------------------- /xrpl/models/requests/manifest.py: -------------------------------------------------------------------------------- 1 | """ 2 | The manifest method reports the current 3 | "manifest" information for a given validator 4 | public key. The "manifest" is the public portion 5 | of that validator's configured token. 6 | """ 7 | 8 | from dataclasses import dataclass, field 9 | 10 | from xrpl.models.requests.request import Request, RequestMethod 11 | from xrpl.models.required import REQUIRED 12 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 13 | 14 | 15 | @require_kwargs_on_init 16 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 17 | class Manifest(Request): 18 | """ 19 | The manifest method reports the current 20 | "manifest" information for a given validator 21 | public key. The "manifest" is the public portion 22 | of that validator's configured token. 23 | """ 24 | 25 | method: RequestMethod = field(default=RequestMethod.MANIFEST, init=False) 26 | public_key: str = REQUIRED # type: ignore 27 | """ 28 | This field is required. 29 | 30 | :meta hide-value: 31 | """ 32 | -------------------------------------------------------------------------------- /xrpl/models/requests/nft_buy_offers.py: -------------------------------------------------------------------------------- 1 | """ 2 | The `nft_buy_offers` method retrieves all of buy offers 3 | for the specified NFToken. 4 | """ 5 | 6 | from dataclasses import dataclass, field 7 | 8 | from xrpl.models.requests.request import LookupByLedgerRequest, Request, RequestMethod 9 | from xrpl.models.required import REQUIRED 10 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 11 | 12 | 13 | @require_kwargs_on_init 14 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 15 | class NFTBuyOffers(Request, LookupByLedgerRequest): 16 | """ 17 | The `nft_buy_offers` method retrieves all of buy offers 18 | for the specified NFToken. 19 | """ 20 | 21 | method: RequestMethod = field(default=RequestMethod.NFT_BUY_OFFERS, init=False) 22 | nft_id: str = REQUIRED # type: ignore 23 | """ 24 | The unique identifier of an NFToken. 25 | The request returns buy offers for this NFToken. This value is required. 26 | 27 | :meta hide-value: 28 | """ 29 | -------------------------------------------------------------------------------- /xrpl/models/requests/nft_history.py: -------------------------------------------------------------------------------- 1 | """ 2 | The `nft_history` method retreives a list of transactions that involved the 3 | specified NFToken. 4 | """ 5 | 6 | from dataclasses import dataclass, field 7 | from typing import Any, Optional 8 | 9 | from xrpl.models.requests.request import LookupByLedgerRequest, Request, RequestMethod 10 | from xrpl.models.required import REQUIRED 11 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 12 | 13 | 14 | @require_kwargs_on_init 15 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 16 | class NFTHistory(Request, LookupByLedgerRequest): 17 | """ 18 | The `nft_history` method retreives a list of transactions that involved the 19 | specified NFToken. 20 | """ 21 | 22 | method: RequestMethod = field(default=RequestMethod.NFT_HISTORY, init=False) 23 | nft_id: str = REQUIRED # type: ignore 24 | """ 25 | The unique identifier of an NFToken. 26 | The request returns past transactions of this NFToken. This value is required. 27 | 28 | :meta hide-value: 29 | """ 30 | 31 | ledger_index_min: Optional[int] = None 32 | ledger_index_max: Optional[int] = None 33 | binary: bool = False 34 | forward: bool = False 35 | limit: Optional[int] = None 36 | # marker data shape is actually undefined in the spec, up to the 37 | # implementation of an individual server 38 | marker: Optional[Any] = None 39 | -------------------------------------------------------------------------------- /xrpl/models/requests/nft_info.py: -------------------------------------------------------------------------------- 1 | """ 2 | The `nft_info` method retrieves all the information about the 3 | NFToken 4 | """ 5 | 6 | from dataclasses import dataclass, field 7 | 8 | from xrpl.models.requests.request import LookupByLedgerRequest, Request, RequestMethod 9 | from xrpl.models.required import REQUIRED 10 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 11 | 12 | 13 | @require_kwargs_on_init 14 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 15 | class NFTInfo(Request, LookupByLedgerRequest): 16 | """ 17 | The `nft_info` method retrieves all the information about the 18 | NFToken 19 | """ 20 | 21 | method: RequestMethod = field(default=RequestMethod.NFT_INFO, init=False) 22 | nft_id: str = REQUIRED # type: ignore 23 | """ 24 | The unique identifier of an NFToken. 25 | The request returns information of this NFToken. This value is required. 26 | 27 | :meta hide-value: 28 | """ 29 | -------------------------------------------------------------------------------- /xrpl/models/requests/nft_sell_offers.py: -------------------------------------------------------------------------------- 1 | """ 2 | The `nft_sell_offers` method retrieves all of sell offers 3 | for the specified NFToken. 4 | """ 5 | 6 | from dataclasses import dataclass, field 7 | 8 | from xrpl.models.requests.request import LookupByLedgerRequest, Request, RequestMethod 9 | from xrpl.models.required import REQUIRED 10 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 11 | 12 | 13 | @require_kwargs_on_init 14 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 15 | class NFTSellOffers(Request, LookupByLedgerRequest): 16 | """ 17 | The `nft_sell_offers` method retrieves all of sell offers 18 | for the specified NFToken. 19 | """ 20 | 21 | method: RequestMethod = field(default=RequestMethod.NFT_SELL_OFFERS, init=False) 22 | nft_id: str = REQUIRED # type: ignore 23 | """ 24 | The unique identifier of an NFToken. 25 | The request returns sell offers for this NFToken. This value is required. 26 | 27 | :meta hide-value: 28 | """ 29 | -------------------------------------------------------------------------------- /xrpl/models/requests/nfts_by_issuer.py: -------------------------------------------------------------------------------- 1 | """ 2 | The `nfts_by_issuer` method retrieves all of the NFTokens 3 | issued by an account 4 | """ 5 | 6 | from dataclasses import dataclass, field 7 | from typing import Any, Optional 8 | 9 | from xrpl.models.requests.request import LookupByLedgerRequest, Request, RequestMethod 10 | from xrpl.models.required import REQUIRED 11 | from xrpl.models.utils import require_kwargs_on_init 12 | 13 | 14 | @require_kwargs_on_init 15 | @dataclass(frozen=True) 16 | class NFTsByIssuer(Request, LookupByLedgerRequest): 17 | """ 18 | The `nfts_by_issuer` method retrieves all of the NFTokens 19 | issued by an account 20 | """ 21 | 22 | method: RequestMethod = field(default=RequestMethod.NFTS_BY_ISSUER, init=False) 23 | issuer: str = REQUIRED # type: ignore 24 | """ 25 | The unique identifier for an account that issues NFTokens 26 | The request returns NFTokens issued by this account. This field is required 27 | 28 | :meta hide-value: 29 | """ 30 | 31 | marker: Optional[Any] = None 32 | nft_taxon: Optional[int] = None 33 | limit: Optional[int] = None 34 | -------------------------------------------------------------------------------- /xrpl/models/requests/no_ripple_check.py: -------------------------------------------------------------------------------- 1 | """ 2 | This request provides a quick way to check the status of the Default Ripple field 3 | for an account and the No Ripple flag of its trust lines, compared with the 4 | recommended settings. 5 | 6 | `See noripple_check `_ 7 | """ 8 | 9 | from dataclasses import dataclass, field 10 | from enum import Enum 11 | from typing import Optional 12 | 13 | from xrpl.models.requests.request import LookupByLedgerRequest, Request, RequestMethod 14 | from xrpl.models.required import REQUIRED 15 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 16 | 17 | 18 | class NoRippleCheckRole(str, Enum): 19 | """Represents the options for the address role in a NoRippleCheckRequest.""" 20 | 21 | GATEWAY = "gateway" 22 | USER = "user" 23 | 24 | 25 | @require_kwargs_on_init 26 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 27 | class NoRippleCheck(Request, LookupByLedgerRequest): 28 | """ 29 | This request provides a quick way to check the status of the Default Ripple field 30 | for an account and the No Ripple flag of its trust lines, compared with the 31 | recommended settings. 32 | 33 | `See noripple_check `_ 34 | """ 35 | 36 | account: str = REQUIRED # type: ignore 37 | """ 38 | This field is required. 39 | 40 | :meta hide-value: 41 | """ 42 | 43 | method: RequestMethod = field(default=RequestMethod.NO_RIPPLE_CHECK, init=False) 44 | role: NoRippleCheckRole = REQUIRED # type: ignore 45 | """ 46 | This field is required. 47 | 48 | :meta hide-value: 49 | """ 50 | 51 | transactions: bool = False 52 | limit: Optional[int] = 300 53 | -------------------------------------------------------------------------------- /xrpl/models/requests/ping.py: -------------------------------------------------------------------------------- 1 | """ 2 | The ping command returns an acknowledgement, so that 3 | clients can test the connection status and latency. 4 | """ 5 | 6 | from dataclasses import dataclass, field 7 | 8 | from xrpl.models.requests.request import Request, RequestMethod 9 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 10 | 11 | 12 | @require_kwargs_on_init 13 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 14 | class Ping(Request): 15 | """ 16 | The ping command returns an acknowledgement, so that 17 | clients can test the connection status and latency. 18 | """ 19 | 20 | method: RequestMethod = field(default=RequestMethod.PING, init=False) 21 | -------------------------------------------------------------------------------- /xrpl/models/requests/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/models/requests/py.typed -------------------------------------------------------------------------------- /xrpl/models/requests/random.py: -------------------------------------------------------------------------------- 1 | """ 2 | The random command provides a random number to be 3 | used as a source of entropy for random number generation by clients. 4 | """ 5 | 6 | from dataclasses import dataclass, field 7 | 8 | from xrpl.models.requests.request import Request, RequestMethod 9 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 10 | 11 | 12 | @require_kwargs_on_init 13 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 14 | class Random(Request): 15 | """ 16 | The random command provides a random number to be 17 | used as a source of entropy for random number generation by clients. 18 | """ 19 | 20 | method: RequestMethod = field(default=RequestMethod.RANDOM, init=False) 21 | -------------------------------------------------------------------------------- /xrpl/models/requests/server_definitions.py: -------------------------------------------------------------------------------- 1 | """ 2 | The server_info command asks the server for a 3 | human-readable version of various information 4 | about the rippled server being queried. 5 | """ 6 | 7 | from dataclasses import dataclass, field 8 | from typing import Optional 9 | 10 | from xrpl.models.requests.request import Request, RequestMethod 11 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 12 | 13 | 14 | @require_kwargs_on_init 15 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 16 | class ServerDefinitions(Request): 17 | """ 18 | The definitions command asks the server for a 19 | human-readable version of various information 20 | about the rippled server being queried. 21 | """ 22 | 23 | method: RequestMethod = field(default=RequestMethod.SERVER_DEFINITIONS, init=False) 24 | 25 | hash: Optional[str] = None 26 | -------------------------------------------------------------------------------- /xrpl/models/requests/server_info.py: -------------------------------------------------------------------------------- 1 | """ 2 | The server_info command asks the server for a 3 | human-readable version of various information 4 | about the rippled server being queried. 5 | """ 6 | 7 | from dataclasses import dataclass, field 8 | 9 | from xrpl.models.requests.request import Request, RequestMethod 10 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 11 | 12 | 13 | @require_kwargs_on_init 14 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 15 | class ServerInfo(Request): 16 | """ 17 | The server_info command asks the server for a 18 | human-readable version of various information 19 | about the rippled server being queried. 20 | """ 21 | 22 | method: RequestMethod = field(default=RequestMethod.SERVER_INFO, init=False) 23 | -------------------------------------------------------------------------------- /xrpl/models/requests/server_state.py: -------------------------------------------------------------------------------- 1 | """ 2 | The server_state command asks the server for various 3 | machine-readable information about the rippled server's 4 | current state. The response is almost the same as the 5 | server_info method, but uses units that are easier to 6 | process instead of easier to read. (For example, XRP 7 | values are given in integer drops instead of scientific 8 | notation or decimal values, and time is given in 9 | milliseconds instead of seconds.) 10 | """ 11 | 12 | from dataclasses import dataclass, field 13 | 14 | from xrpl.models.requests.request import Request, RequestMethod 15 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 16 | 17 | 18 | @require_kwargs_on_init 19 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 20 | class ServerState(Request): 21 | """ 22 | The server_state command asks the server for various 23 | machine-readable information about the rippled server's 24 | current state. The response is almost the same as the 25 | server_info method, but uses units that are easier to 26 | process instead of easier to read. (For example, XRP 27 | values are given in integer drops instead of scientific 28 | notation or decimal values, and time is given in 29 | milliseconds instead of seconds.) 30 | """ 31 | 32 | method: RequestMethod = field(default=RequestMethod.SERVER_STATE, init=False) 33 | -------------------------------------------------------------------------------- /xrpl/models/requests/transaction_entry.py: -------------------------------------------------------------------------------- 1 | """ 2 | The transaction_entry method retrieves information on a single transaction from a 3 | specific ledger version. (The tx method, by contrast, searches all ledgers for the 4 | specified transaction. We recommend using that method instead.) 5 | 6 | `See transaction_entry `_ 7 | """ 8 | 9 | from __future__ import annotations 10 | 11 | from dataclasses import dataclass, field 12 | 13 | from xrpl.models.requests.request import LookupByLedgerRequest, Request, RequestMethod 14 | from xrpl.models.required import REQUIRED 15 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 16 | 17 | 18 | @require_kwargs_on_init 19 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 20 | class TransactionEntry(Request, LookupByLedgerRequest): 21 | """ 22 | The transaction_entry method retrieves information on a single transaction from a 23 | specific ledger version. (The tx method, by contrast, searches all ledgers for the 24 | specified transaction. We recommend using that method instead.) 25 | 26 | `See transaction_entry `_ 27 | """ 28 | 29 | method: RequestMethod = field(default=RequestMethod.TRANSACTION_ENTRY, init=False) 30 | tx_hash: str = REQUIRED # type: ignore 31 | """ 32 | This field is required. 33 | 34 | :meta hide-value: 35 | """ 36 | -------------------------------------------------------------------------------- /xrpl/models/required.py: -------------------------------------------------------------------------------- 1 | """ 2 | A sentinel object used to determine if a given field is not set. Using this 3 | allows us to not worry about argument ordering and treat all arguments to 4 | __init__ as kwargs. 5 | """ 6 | 7 | from typing_extensions import Final 8 | 9 | REQUIRED: Final[object] = object() 10 | -------------------------------------------------------------------------------- /xrpl/models/transactions/check_cancel.py: -------------------------------------------------------------------------------- 1 | """Model for CheckCancel transaction type.""" 2 | 3 | from dataclasses import dataclass, field 4 | 5 | from xrpl.models.required import REQUIRED 6 | from xrpl.models.transactions.transaction import Transaction 7 | from xrpl.models.transactions.types import TransactionType 8 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 9 | 10 | 11 | @require_kwargs_on_init 12 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 13 | class CheckCancel(Transaction): 14 | """ 15 | Represents a `CheckCancel `_ transaction, 16 | which cancels an unredeemed Check, removing it from the ledger 17 | without sending any money. The source or the destination of the check 18 | can cancel a Check at any time using this transaction type. If the 19 | Check has expired, any address can cancel it. 20 | """ 21 | 22 | check_id: str = REQUIRED # type: ignore 23 | """ 24 | The ID of the `Check ledger object 25 | `_ to cancel, as a 64-character 26 | hexadecimal string. This field is required. 27 | 28 | :meta hide-value: 29 | """ 30 | 31 | transaction_type: TransactionType = field( 32 | default=TransactionType.CHECK_CANCEL, 33 | init=False, 34 | ) 35 | -------------------------------------------------------------------------------- /xrpl/models/transactions/credential_accept.py: -------------------------------------------------------------------------------- 1 | """Model for CredentialAccept transaction type.""" 2 | 3 | from dataclasses import dataclass, field 4 | from typing import Dict 5 | 6 | from typing_extensions import Self 7 | 8 | from xrpl.models.required import REQUIRED 9 | from xrpl.models.transactions.transaction import Transaction 10 | from xrpl.models.transactions.types import TransactionType 11 | from xrpl.models.utils import ( 12 | KW_ONLY_DATACLASS, 13 | get_credential_type_error, 14 | require_kwargs_on_init, 15 | ) 16 | 17 | 18 | @require_kwargs_on_init 19 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 20 | class CredentialAccept(Transaction): 21 | """This transaction accepts a credential issued to the Account (i.e. the Account is 22 | the Subject of the Credential object). The credential is not considered valid until 23 | it has been transferred/accepted. 24 | """ 25 | 26 | account: str = REQUIRED # type: ignore 27 | """ 28 | The subject of the credential. 29 | """ 30 | 31 | issuer: str = REQUIRED # type: ignore 32 | """ 33 | The issuer of the credential. 34 | """ 35 | 36 | credential_type: str = REQUIRED # type: ignore 37 | """ 38 | A hex-encoded value to identify the type of credential from the issuer. 39 | """ 40 | 41 | transaction_type: TransactionType = field( 42 | default=TransactionType.CREDENTIAL_ACCEPT, 43 | init=False, 44 | ) 45 | 46 | def _get_errors(self: Self) -> Dict[str, str]: 47 | errors = super()._get_errors() 48 | if ( 49 | cred_type_error := get_credential_type_error(self.credential_type) 50 | ) is not None: 51 | errors["credential_type"] = cred_type_error 52 | return errors 53 | -------------------------------------------------------------------------------- /xrpl/models/transactions/did_delete.py: -------------------------------------------------------------------------------- 1 | """Model for DIDDelete transaction type.""" 2 | 3 | from __future__ import annotations 4 | 5 | from dataclasses import dataclass, field 6 | 7 | from xrpl.models.transactions.transaction import Transaction 8 | from xrpl.models.transactions.types import TransactionType 9 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 10 | 11 | 12 | @require_kwargs_on_init 13 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 14 | class DIDDelete(Transaction): 15 | """Represents a DIDDelete transaction.""" 16 | 17 | transaction_type: TransactionType = field( 18 | default=TransactionType.DID_DELETE, 19 | init=False, 20 | ) 21 | -------------------------------------------------------------------------------- /xrpl/models/transactions/escrow_cancel.py: -------------------------------------------------------------------------------- 1 | """Model for EscrowCancel transaction type.""" 2 | 3 | from dataclasses import dataclass, field 4 | 5 | from xrpl.models.required import REQUIRED 6 | from xrpl.models.transactions.transaction import Transaction 7 | from xrpl.models.transactions.types import TransactionType 8 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 9 | 10 | 11 | @require_kwargs_on_init 12 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 13 | class EscrowCancel(Transaction): 14 | """ 15 | Represents an `EscrowCancel `_ 16 | transaction, which returns escrowed XRP to the sender after the Escrow has 17 | expired. 18 | """ 19 | 20 | owner: str = REQUIRED # type: ignore 21 | """ 22 | The address of the account that funded the Escrow. This field is required. 23 | 24 | :meta hide-value: 25 | """ 26 | 27 | offer_sequence: int = REQUIRED # type: ignore 28 | """ 29 | Transaction sequence (or Ticket number) of the EscrowCreate transaction 30 | that created the Escrow. This field is required. 31 | 32 | :meta hide-value: 33 | """ 34 | 35 | transaction_type: TransactionType = field( 36 | default=TransactionType.ESCROW_CANCEL, 37 | init=False, 38 | ) 39 | -------------------------------------------------------------------------------- /xrpl/models/transactions/mptoken_issuance_destroy.py: -------------------------------------------------------------------------------- 1 | """Model for MPTokenIssuanceDestroy transaction type.""" 2 | 3 | from __future__ import annotations 4 | 5 | from dataclasses import dataclass, field 6 | 7 | from xrpl.models.required import REQUIRED 8 | from xrpl.models.transactions.transaction import Transaction 9 | from xrpl.models.transactions.types import TransactionType 10 | from xrpl.models.utils import require_kwargs_on_init 11 | 12 | 13 | @require_kwargs_on_init 14 | @dataclass(frozen=True) 15 | class MPTokenIssuanceDestroy(Transaction): 16 | """ 17 | The MPTokenIssuanceDestroy transaction is used to remove an MPTokenIssuance object 18 | from the directory node in which it is being held, effectively removing the token 19 | from the ledger. If this operation succeeds, the corresponding 20 | MPTokenIssuance is removed and the owner’s reserve requirement is reduced by one. 21 | This operation must fail if there are any holders who have non-zero balances. 22 | """ 23 | 24 | mptoken_issuance_id: str = REQUIRED # type: ignore 25 | """Identifies the MPTokenIssuance object to be removed by the transaction.""" 26 | 27 | transaction_type: TransactionType = field( 28 | default=TransactionType.MPTOKEN_ISSUANCE_DESTROY, 29 | init=False, 30 | ) 31 | -------------------------------------------------------------------------------- /xrpl/models/transactions/offer_cancel.py: -------------------------------------------------------------------------------- 1 | """Model for OfferCancel transaction type.""" 2 | 3 | from dataclasses import dataclass, field 4 | 5 | from xrpl.models.required import REQUIRED 6 | from xrpl.models.transactions.transaction import Transaction 7 | from xrpl.models.transactions.types import TransactionType 8 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 9 | 10 | 11 | @require_kwargs_on_init 12 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 13 | class OfferCancel(Transaction): 14 | """ 15 | Represents an `OfferCancel `_ transaction, 16 | which removes an Offer object from the `decentralized exchange 17 | `_. 18 | """ 19 | 20 | offer_sequence: int = REQUIRED # type: ignore 21 | """ 22 | The Sequence number (or Ticket number) of a previous OfferCreate 23 | transaction. If specified, cancel any Offer object in the ledger that was 24 | created by that transaction. It is not considered an error if the Offer 25 | specified does not exist. 26 | """ 27 | 28 | transaction_type: TransactionType = field( 29 | default=TransactionType.OFFER_CANCEL, 30 | init=False, 31 | ) 32 | -------------------------------------------------------------------------------- /xrpl/models/transactions/oracle_delete.py: -------------------------------------------------------------------------------- 1 | """Model for OracleDelete transaction type.""" 2 | 3 | from __future__ import annotations 4 | 5 | from dataclasses import dataclass, field 6 | 7 | from xrpl.models.required import REQUIRED 8 | from xrpl.models.transactions.transaction import Transaction 9 | from xrpl.models.transactions.types import TransactionType 10 | from xrpl.models.utils import require_kwargs_on_init 11 | 12 | 13 | @require_kwargs_on_init 14 | @dataclass(frozen=True) 15 | class OracleDelete(Transaction): 16 | """Delete an Oracle ledger entry.""" 17 | 18 | account: str = REQUIRED # type: ignore 19 | """This account must match the account in the Owner field of the Oracle object.""" 20 | 21 | oracle_document_id: int = REQUIRED # type: ignore 22 | """A unique identifier of the price oracle for the Account.""" 23 | 24 | transaction_type: TransactionType = field( 25 | default=TransactionType.ORACLE_DELETE, 26 | init=False, 27 | ) 28 | -------------------------------------------------------------------------------- /xrpl/models/transactions/permissioned_domain_delete.py: -------------------------------------------------------------------------------- 1 | """Model for PermissionedDomainDelete transaction type.""" 2 | 3 | import re 4 | from dataclasses import dataclass, field 5 | from typing import Dict, Final, Pattern 6 | 7 | from typing_extensions import Self 8 | 9 | from xrpl.models.required import REQUIRED 10 | from xrpl.models.transactions.transaction import Transaction 11 | from xrpl.models.transactions.types import TransactionType 12 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 13 | 14 | _DOMAIN_ID_REGEX: Final[Pattern[str]] = re.compile("[A-F0-9]{64}") 15 | DOMAIN_ID_LENGTH: Final[int] = 64 16 | 17 | 18 | @require_kwargs_on_init 19 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 20 | class PermissionedDomainDelete(Transaction): 21 | """This transaction deletes a PermissionedDomain object.""" 22 | 23 | domain_id: str = REQUIRED # type: ignore 24 | """The domain to delete.""" 25 | 26 | transaction_type: TransactionType = field( 27 | default=TransactionType.PERMISSIONED_DOMAIN_DELETE, 28 | init=False, 29 | ) 30 | """The transaction type (PermissionedDomainDelete).""" 31 | 32 | def _get_errors(self: Self) -> Dict[str, str]: 33 | errors = super()._get_errors() 34 | 35 | if len(self.domain_id) != DOMAIN_ID_LENGTH: 36 | errors["PermissionedDomainDelete"] = ( 37 | f"domain_id must be {DOMAIN_ID_LENGTH} characters long." 38 | ) 39 | elif not _DOMAIN_ID_REGEX.fullmatch(self.domain_id): 40 | errors["PermissionedDomainDelete"] = ( 41 | "domain_id does not conform to hex format." 42 | ) 43 | 44 | return errors 45 | -------------------------------------------------------------------------------- /xrpl/models/transactions/pseudo_transactions/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Model objects for specific `types of Pseudo-Transactions 3 | `_ in the XRP Ledger. 4 | """ 5 | 6 | from xrpl.models.transactions.pseudo_transactions.enable_amendment import ( 7 | EnableAmendment, 8 | EnableAmendmentFlag, 9 | EnableAmendmentFlagInterface, 10 | ) 11 | from xrpl.models.transactions.pseudo_transactions.set_fee import SetFee 12 | from xrpl.models.transactions.pseudo_transactions.unl_modify import UNLModify 13 | 14 | __all__ = [ 15 | "EnableAmendment", 16 | "EnableAmendmentFlag", 17 | "SetFee", 18 | "UNLModify", 19 | "EnableAmendmentFlagInterface", 20 | ] 21 | -------------------------------------------------------------------------------- /xrpl/models/transactions/pseudo_transactions/pseudo_transaction.py: -------------------------------------------------------------------------------- 1 | """The base model for all pseudo-transactions and their nested object types.""" 2 | 3 | from dataclasses import dataclass, field 4 | 5 | from xrpl.models.required import REQUIRED 6 | from xrpl.models.transactions.transaction import Transaction 7 | from xrpl.models.transactions.types import PseudoTransactionType 8 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 9 | 10 | _ACCOUNT_ZERO = "rrrrrrrrrrrrrrrrrrrrrhoLvTp" # base58 encoding of the value `0` 11 | 12 | 13 | @require_kwargs_on_init 14 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 15 | class PseudoTransaction(Transaction): 16 | """ 17 | Pseudo-transactions are never submitted by users, nor propagated through the 18 | network. Instead, a server may choose to inject pseudo-transactions in a proposed 19 | ledger directly according to specific protocol rules. If enough servers inject an 20 | identical pseudo-transaction for it to be approved by the consensus process, then 21 | the pseudo-transaction becomes included in the ledger, and appears in ledger data 22 | thereafter. 23 | """ 24 | 25 | account: str = field(default=_ACCOUNT_ZERO, init=False) 26 | fee: str = field(default="0", init=False) 27 | sequence: int = field(default=0, init=False) 28 | signing_pub_key: str = field(default="", init=False) 29 | txn_signature: str = field(default="", init=False) 30 | source_tag: None = field(default=None, init=False) 31 | transaction_type: PseudoTransactionType = REQUIRED # type: ignore 32 | -------------------------------------------------------------------------------- /xrpl/models/transactions/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/models/transactions/py.typed -------------------------------------------------------------------------------- /xrpl/models/transactions/set_regular_key.py: -------------------------------------------------------------------------------- 1 | """Model for SetRegularKey transaction type.""" 2 | 3 | from dataclasses import dataclass, field 4 | from typing import Optional 5 | 6 | from xrpl.models.transactions.transaction import Transaction 7 | from xrpl.models.transactions.types import TransactionType 8 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 9 | 10 | 11 | @require_kwargs_on_init 12 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 13 | class SetRegularKey(Transaction): 14 | """ 15 | Represents a `SetRegularKey `_ 16 | transaction, which assigns, changes, or removes a secondary "regular" key pair 17 | associated with an account. 18 | """ 19 | 20 | regular_key: Optional[str] = None 21 | """ 22 | The classic address derived from the key pair to authorize for this 23 | account. If omitted, removes any existing regular key pair from the 24 | account. Must not match the account's master key pair. 25 | """ 26 | 27 | transaction_type: TransactionType = field( 28 | default=TransactionType.SET_REGULAR_KEY, 29 | init=False, 30 | ) 31 | -------------------------------------------------------------------------------- /xrpl/models/transactions/ticket_create.py: -------------------------------------------------------------------------------- 1 | """Model for TicketCreate transaction type.""" 2 | 3 | from dataclasses import dataclass, field 4 | 5 | from xrpl.models.required import REQUIRED 6 | from xrpl.models.transactions.transaction import Transaction 7 | from xrpl.models.transactions.types import TransactionType 8 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 9 | 10 | 11 | @require_kwargs_on_init 12 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 13 | class TicketCreate(Transaction): 14 | """ 15 | A TicketCreate transaction sets aside one or more `sequence numbers 16 | `_ as `Tickets 17 | `_. 18 | """ 19 | 20 | ticket_count: int = REQUIRED # type: ignore 21 | """ 22 | How many Tickets to create. This must be a positive number and cannot cause the 23 | account to own more than 250 Tickets after executing this transaction. 24 | :meta hide-value: 25 | """ 26 | 27 | transaction_type: TransactionType = field( 28 | default=TransactionType.TICKET_CREATE, 29 | init=False, 30 | ) 31 | -------------------------------------------------------------------------------- /xrpl/models/transactions/types/__init__.py: -------------------------------------------------------------------------------- 1 | """Transaction and pseudo-transaction type Enums.""" 2 | 3 | from xrpl.models.transactions.types.pseudo_transaction_type import PseudoTransactionType 4 | from xrpl.models.transactions.types.transaction_type import TransactionType 5 | 6 | __all__ = ["PseudoTransactionType", "TransactionType"] 7 | -------------------------------------------------------------------------------- /xrpl/models/transactions/types/pseudo_transaction_type.py: -------------------------------------------------------------------------------- 1 | """Enum containing the different Psuedo-Transaction types.""" 2 | 3 | from enum import Enum 4 | 5 | 6 | class PseudoTransactionType(str, Enum): 7 | """Enum containing the different Psuedo-Transaction types.""" 8 | 9 | ENABLE_AMENDMENT = "EnableAmendment" 10 | SET_FEE = "SetFee" 11 | UNL_MODIFY = "UNLModify" 12 | -------------------------------------------------------------------------------- /xrpl/models/types.py: -------------------------------------------------------------------------------- 1 | """ 2 | Internal helper types for xrpl.models 3 | 4 | :meta private: 5 | """ 6 | 7 | from typing import Any, Dict, List, Union 8 | 9 | # The type of a parsed model in python, after it is loaded from a JSON string 10 | # but before it is loaded into a model. Internal representations use 11 | # snake_cased keys for the dictionary prior to loading into a model, but those 12 | # keys must be PascalCased when sent to/received from a validator. 13 | # 14 | # TODO these Anys can be resolved if/when mypy supports recursive types. The 15 | # correct type of this should be: 16 | # _XRPL_VALUE_TYPE = Union[ 17 | # str, 18 | # int, 19 | # List[_XRPL_VALUE_TYPE], 20 | # Dict[str, _XRPL_VALUE_TYPE] 21 | # ] 22 | # Here is their GH issue https://github.com/python/mypy/issues/731 23 | XRPL_VALUE_TYPE = Union[str, int, List[Any], Dict[str, Any]] 24 | -------------------------------------------------------------------------------- /xrpl/models/xchain_bridge.py: -------------------------------------------------------------------------------- 1 | """A XChainBridge represents a cross-chain bridge.""" 2 | 3 | from __future__ import annotations 4 | 5 | from dataclasses import dataclass 6 | 7 | from xrpl.models.base_model import BaseModel 8 | from xrpl.models.currencies import Currency 9 | from xrpl.models.utils import KW_ONLY_DATACLASS, require_kwargs_on_init 10 | 11 | 12 | @require_kwargs_on_init 13 | @dataclass(frozen=True, **KW_ONLY_DATACLASS) 14 | class XChainBridge(BaseModel): 15 | """A XChainBridge represents a cross-chain bridge.""" 16 | 17 | locking_chain_door: str 18 | """ 19 | The door account on the locking chain. 20 | """ 21 | 22 | locking_chain_issue: Currency 23 | """ 24 | The asset that is locked and unlocked on the locking chain. 25 | """ 26 | 27 | issuing_chain_door: str 28 | """ 29 | The door account on the issuing chain. For an XRP-XRP bridge, this must be 30 | the genesis account (the account that is created when the network is first 31 | started, which contains all of the XRP). 32 | """ 33 | 34 | issuing_chain_issue: Currency 35 | """ 36 | The asset that is minted and burned on the issuing chain. For an IOU-IOU 37 | bridge, the issuer of the asset must be the door account on the issuing 38 | chain, to avoid supply issues. 39 | """ 40 | -------------------------------------------------------------------------------- /xrpl/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/py.typed -------------------------------------------------------------------------------- /xrpl/transaction/__init__.py: -------------------------------------------------------------------------------- 1 | """Methods for working with transactions on the XRP Ledger.""" 2 | 3 | from xrpl.asyncio.transaction import ( 4 | XRPLReliableSubmissionException, 5 | transaction_json_to_binary_codec_form, 6 | ) 7 | from xrpl.transaction.batch_signers import ( 8 | combine_batch_signers, 9 | sign_multiaccount_batch, 10 | ) 11 | from xrpl.transaction.main import ( 12 | autofill, 13 | autofill_and_sign, 14 | sign, 15 | sign_and_submit, 16 | simulate, 17 | submit, 18 | ) 19 | from xrpl.transaction.multisign import multisign 20 | from xrpl.transaction.reliable_submission import submit_and_wait 21 | 22 | __all__ = [ 23 | "autofill", 24 | "autofill_and_sign", 25 | "combine_batch_signers", 26 | "multisign", 27 | "sign", 28 | "sign_and_submit", 29 | "sign_multiaccount_batch", 30 | "simulate", 31 | "submit", 32 | "submit_and_wait", 33 | "transaction_json_to_binary_codec_form", 34 | "XRPLReliableSubmissionException", 35 | ] 36 | -------------------------------------------------------------------------------- /xrpl/transaction/multisign.py: -------------------------------------------------------------------------------- 1 | """Multisign transaction methods with XRPL transactions.""" 2 | 3 | from typing import List 4 | 5 | from xrpl.core.addresscodec import decode_classic_address 6 | from xrpl.models.transactions.transaction import Signer, Transaction 7 | 8 | 9 | def multisign(transaction: Transaction, tx_list: List[Transaction]) -> Transaction: 10 | """ 11 | Takes several transactions with Signer fields and creates a 12 | single transaction with all Signers that then gets signed and returned. 13 | 14 | Args: 15 | transaction: the transaction to be multisigned. 16 | tx_list: a list of signed transactions to combine into a single multisigned 17 | transaction. 18 | 19 | Returns: 20 | The multisigned transaction. 21 | """ 22 | decoded_tx_signers = [tx.to_xrpl()["Signers"][0]["Signer"] for tx in tx_list] 23 | 24 | tx_dict = transaction.to_dict() 25 | tx_dict["signers"] = [ 26 | Signer( 27 | account=decoded_tx_signer["Account"], 28 | txn_signature=decoded_tx_signer["TxnSignature"], 29 | signing_pub_key=decoded_tx_signer["SigningPubKey"], 30 | ) 31 | for decoded_tx_signer in decoded_tx_signers 32 | ] 33 | tx_dict["signers"].sort(key=lambda signer: decode_classic_address(signer.account)) 34 | 35 | return Transaction.from_dict(tx_dict) 36 | -------------------------------------------------------------------------------- /xrpl/transaction/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/transaction/py.typed -------------------------------------------------------------------------------- /xrpl/utils/__init__.py: -------------------------------------------------------------------------------- 1 | """Convenience utilities for the XRP Ledger""" 2 | 3 | from xrpl.utils.get_nftoken_id import get_nftoken_id 4 | from xrpl.utils.get_xchain_claim_id import get_xchain_claim_id 5 | from xrpl.utils.parse_nftoken_id import parse_nftoken_id 6 | from xrpl.utils.str_conversions import hex_to_str, str_to_hex 7 | from xrpl.utils.time_conversions import ( 8 | XRPLTimeRangeException, 9 | datetime_to_ripple_time, 10 | posix_to_ripple_time, 11 | ripple_time_to_datetime, 12 | ripple_time_to_posix, 13 | ) 14 | from xrpl.utils.txn_parser import ( 15 | get_balance_changes, 16 | get_final_balances, 17 | get_order_book_changes, 18 | ) 19 | from xrpl.utils.xrp_conversions import XRPRangeException, drops_to_xrp, xrp_to_drops 20 | 21 | __all__ = [ 22 | "str_to_hex", 23 | "hex_to_str", 24 | "xrp_to_drops", 25 | "drops_to_xrp", 26 | "ripple_time_to_datetime", 27 | "datetime_to_ripple_time", 28 | "ripple_time_to_posix", 29 | "posix_to_ripple_time", 30 | "XRPRangeException", 31 | "XRPLTimeRangeException", 32 | "get_balance_changes", 33 | "get_final_balances", 34 | "get_order_book_changes", 35 | "get_nftoken_id", 36 | "parse_nftoken_id", 37 | "get_xchain_claim_id", 38 | ] 39 | -------------------------------------------------------------------------------- /xrpl/utils/get_xchain_claim_id.py: -------------------------------------------------------------------------------- 1 | """Utils to get an XChainClaimID from metadata.""" 2 | 3 | from xrpl.models.transactions.metadata import TransactionMetadata, isCreatedNode 4 | 5 | 6 | def get_xchain_claim_id(meta: TransactionMetadata) -> str: 7 | """ 8 | Gets the XChainClaimID from a recently-submitted XChainCreateClaimID transaction. 9 | 10 | Args: 11 | meta: Metadata from the response to submitting an XChainCreateClaimID 12 | transaction. 13 | 14 | Returns: 15 | The newly created XChainClaimID. 16 | 17 | Raises: 18 | TypeError: if given something other than metadata (e.g. the full 19 | transaction response). 20 | """ 21 | if meta is None or meta.get("AffectedNodes") is None: 22 | raise TypeError( 23 | f"""Unable to parse the parameter given to get_xchain_claim_id. 24 | 'meta' must be the metadata from an XChainCreateClaimID transaction. 25 | Received {meta} instead.""" 26 | ) 27 | 28 | affected_nodes = [ 29 | node 30 | for node in meta["AffectedNodes"] 31 | if isCreatedNode(node) 32 | and node["CreatedNode"]["LedgerEntryType"] == "XChainOwnedClaimID" 33 | ] 34 | 35 | if len(affected_nodes) == 0: 36 | raise TypeError("No XChainOwnedClaimID created.") 37 | 38 | if len(affected_nodes) > 1: 39 | # Sanity check - should never happen 40 | raise TypeError( 41 | "Multiple XChainOwnedClaimIDs were somehow created. Please report this " 42 | "error." 43 | ) 44 | 45 | # Get the NFTokenID which wasn't there before this transaction completed. 46 | return affected_nodes[0]["CreatedNode"]["NewFields"]["XChainClaimID"] 47 | -------------------------------------------------------------------------------- /xrpl/utils/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/utils/py.typed -------------------------------------------------------------------------------- /xrpl/utils/str_conversions.py: -------------------------------------------------------------------------------- 1 | """Various useful string conversions utilities for XRPL.""" 2 | 3 | 4 | def str_to_hex(input: str) -> str: 5 | """ 6 | Convert a UTF-8-encoded string into hexadecimal encoding. 7 | XRPL uses hex strings as inputs in fields like `domain` 8 | in the `AccountSet` transaction. 9 | 10 | Args: 11 | input: UTF-8-encoded string to convert 12 | 13 | Returns: 14 | Input encoded as a hex string. 15 | """ 16 | return input.encode("utf-8").hex() 17 | 18 | 19 | def hex_to_str(input: str) -> str: 20 | """ 21 | Convert a hex string into a human-readable string. 22 | XRPL uses hex strings as inputs in fields like `domain` 23 | in the `AccountSet` transaction. 24 | 25 | Args: 26 | input: hex-encoded string to convert 27 | 28 | Returns: 29 | Input encoded as a human-readable string. 30 | """ 31 | return bytes.fromhex(input).decode() 32 | -------------------------------------------------------------------------------- /xrpl/utils/txn_parser/__init__.py: -------------------------------------------------------------------------------- 1 | """Functions to parse a transaction.""" 2 | 3 | from xrpl.utils.txn_parser.get_balance_changes import get_balance_changes 4 | from xrpl.utils.txn_parser.get_final_balances import get_final_balances 5 | from xrpl.utils.txn_parser.get_order_book_changes import get_order_book_changes 6 | 7 | __all__ = ["get_balance_changes", "get_final_balances", "get_order_book_changes"] 8 | -------------------------------------------------------------------------------- /xrpl/utils/txn_parser/get_final_balances.py: -------------------------------------------------------------------------------- 1 | """Parse final balances of every account involved in the given transaction.""" 2 | 3 | from decimal import Decimal 4 | from typing import List, Optional 5 | 6 | from xrpl.models import TransactionMetadata 7 | from xrpl.utils.txn_parser.utils import ( 8 | AccountBalances, 9 | NormalizedNode, 10 | derive_account_balances, 11 | get_value, 12 | ) 13 | 14 | 15 | def get_final_balances(metadata: TransactionMetadata) -> List[AccountBalances]: 16 | """ 17 | Parse all final balances from a transaction's metadata. 18 | 19 | Args: 20 | metadata: Transactions metadata. 21 | 22 | Returns: 23 | All final balances caused by a transaction. 24 | The final balances are grouped by the affected account addresses. 25 | """ 26 | return derive_account_balances(metadata, _compute_final_balance) 27 | 28 | 29 | def _compute_final_balance(node: NormalizedNode) -> Optional[Decimal]: 30 | """ 31 | Get the final balance from a node. 32 | 33 | Args: 34 | node: The affected node. 35 | 36 | Returns: 37 | The final balance. 38 | """ 39 | value: Optional[Decimal] = None 40 | new_fields = node.get("NewFields") 41 | final_fields = node.get("FinalFields") 42 | if new_fields is not None: 43 | balance = new_fields.get("Balance") 44 | if balance is not None: 45 | value = get_value(balance) 46 | elif final_fields is not None: 47 | balance = final_fields.get("Balance") 48 | if balance is not None: 49 | value = get_value(balance) 50 | if value is None or value == Decimal(0): 51 | return None 52 | return value 53 | -------------------------------------------------------------------------------- /xrpl/utils/txn_parser/get_order_book_changes.py: -------------------------------------------------------------------------------- 1 | """Parse offer changes of every offer object involved in the given transaction.""" 2 | 3 | from typing import List 4 | 5 | from xrpl.models import TransactionMetadata 6 | from xrpl.utils.txn_parser.utils import AccountOfferChanges, compute_order_book_changes 7 | 8 | 9 | def get_order_book_changes(metadata: TransactionMetadata) -> List[AccountOfferChanges]: 10 | """ 11 | Parse all order book changes from a transaction's metadata. 12 | 13 | Args: 14 | metadata: Transactions metadata. 15 | 16 | Returns: 17 | All offer changes caused by the transaction. 18 | The offer changes are grouped by their owner accounts. 19 | """ 20 | return compute_order_book_changes(metadata) 21 | -------------------------------------------------------------------------------- /xrpl/utils/txn_parser/utils/__init__.py: -------------------------------------------------------------------------------- 1 | """Utility functions for the transaction parser.""" 2 | 3 | from xrpl.utils.txn_parser.utils.balance_parser import derive_account_balances 4 | from xrpl.utils.txn_parser.utils.nodes import NormalizedNode, normalize_nodes 5 | from xrpl.utils.txn_parser.utils.order_book_parser import compute_order_book_changes 6 | from xrpl.utils.txn_parser.utils.parser import get_value 7 | from xrpl.utils.txn_parser.utils.types import AccountBalances, AccountOfferChanges 8 | 9 | __all__ = [ 10 | "get_value", 11 | "derive_account_balances", 12 | "NormalizedNode", 13 | "normalize_nodes", 14 | "AccountBalances", 15 | "AccountOfferChanges", 16 | "compute_order_book_changes", 17 | ] 18 | -------------------------------------------------------------------------------- /xrpl/utils/txn_parser/utils/parser.py: -------------------------------------------------------------------------------- 1 | """Helper functions for parsers.""" 2 | 3 | from decimal import Decimal 4 | from typing import Any, Dict, List, Union 5 | 6 | from xrpl.utils.txn_parser.utils.types import ( 7 | AccountBalance, 8 | AccountOfferChange, 9 | CurrencyAmount, 10 | ) 11 | 12 | 13 | def get_value(balance: Union[CurrencyAmount, Dict[str, str], str]) -> Decimal: 14 | """ 15 | Get a currency amount's value. 16 | 17 | Args: 18 | balance: Account's balance. 19 | 20 | Returns: 21 | The currency amount's value. 22 | """ 23 | if isinstance(balance, str): 24 | return Decimal(balance) 25 | return Decimal(balance["value"]) 26 | 27 | 28 | def group_by_account( 29 | account_objects: Union[List[AccountBalance], List[AccountOfferChange]], 30 | ) -> Dict[str, Any]: 31 | """ 32 | Groups the account objects in one list for each account. 33 | 34 | Args: 35 | account_objects: All computed objects. 36 | 37 | Returns: 38 | The grouped computed objects. 39 | """ 40 | grouped_objects: Dict[str, Any] = {} 41 | for object in account_objects: 42 | if object.get("account") is not None: 43 | account = str(object.get("account")) 44 | else: 45 | account = str(object.get("maker_account")) 46 | grouped_objects.setdefault(account, []).append(object) 47 | return grouped_objects 48 | -------------------------------------------------------------------------------- /xrpl/utils/txn_parser/utils/types.py: -------------------------------------------------------------------------------- 1 | """Types used by the parser.""" 2 | 3 | from typing import List 4 | 5 | from typing_extensions import Literal, NotRequired, TypedDict 6 | 7 | 8 | class Balance(TypedDict): 9 | """A account's balance model.""" 10 | 11 | currency: str 12 | """The currency code.""" 13 | 14 | value: str 15 | """The amount of the currency.""" 16 | 17 | issuer: NotRequired[str] 18 | """The issuer of the currency. This value is optional.""" 19 | 20 | 21 | class AccountBalance(TypedDict): 22 | """A single account balance.""" 23 | 24 | account: str 25 | """The affected account.""" 26 | balance: Balance 27 | """The balance.""" 28 | 29 | 30 | class AccountBalances(TypedDict): 31 | """A model representing an account's balances.""" 32 | 33 | account: str 34 | balances: List[Balance] 35 | 36 | 37 | class CurrencyAmount(Balance): 38 | """A currency amount model. Has the same fields as `Balance`""" 39 | 40 | pass 41 | 42 | 43 | class OfferChange(TypedDict): 44 | """A single offer change.""" 45 | 46 | flags: int 47 | taker_gets: CurrencyAmount 48 | taker_pays: CurrencyAmount 49 | sequence: int 50 | status: Literal["created", "partially-filled", "filled", "cancelled"] 51 | maker_exchange_rate: str 52 | expiration_time: NotRequired[int] 53 | 54 | 55 | class AccountOfferChange(TypedDict): 56 | """A model representing an account's offer change.""" 57 | 58 | maker_account: str 59 | offer_change: OfferChange 60 | 61 | 62 | class AccountOfferChanges(TypedDict): 63 | """A model representing an account's offer changes.""" 64 | 65 | maker_account: str 66 | offer_changes: List[OfferChange] 67 | -------------------------------------------------------------------------------- /xrpl/wallet/__init__.py: -------------------------------------------------------------------------------- 1 | """Methods for working with XRPL wallets.""" 2 | 3 | from xrpl.asyncio.wallet import XRPLFaucetException 4 | from xrpl.wallet.main import Wallet 5 | from xrpl.wallet.wallet_generation import generate_faucet_wallet 6 | 7 | __all__ = ["Wallet", "generate_faucet_wallet", "XRPLFaucetException"] 8 | -------------------------------------------------------------------------------- /xrpl/wallet/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-py/cd6b7a263ecc4709f737cd7d6f285760b7f53f73/xrpl/wallet/py.typed --------------------------------------------------------------------------------