diff --git a/CHANGELOG.md b/CHANGELOG.md index 10f2f095..bb6b0fe4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ Release History ============== ### Pending +#### Update +- feat: add support for Soroban PRC's `getTransactions` and `getFeeStats` API interfaces. ### Version 11.0.0 diff --git a/stellar_sdk/soroban_rpc.py b/stellar_sdk/soroban_rpc.py index 67779f65..74c01b09 100644 --- a/stellar_sdk/soroban_rpc.py +++ b/stellar_sdk/soroban_rpc.py @@ -75,7 +75,7 @@ class PaginationOptions(BaseModel): class GetEventsRequest(BaseModel): """Response for JSON-RPC method getEvents. - See `getEvents documentation `__ for + See `getEvents documentation `__ for more information. """ @@ -87,7 +87,7 @@ class GetEventsRequest(BaseModel): class GetEventsResponse(BaseModel): """Response for JSON-RPC method getEvents. - See `getEvents documentation `__ for + See `getEvents documentation `__ for more information. """ @@ -99,7 +99,7 @@ class GetEventsResponse(BaseModel): class GetLedgerEntriesRequest(BaseModel): """Response for JSON-RPC method getLedgerEntries. - See `getLedgerEntries documentation `__ for + See `getLedgerEntries documentation `__ for more information.""" keys: Sequence[str] @@ -115,7 +115,7 @@ class LedgerEntryResult(BaseModel): class GetLedgerEntriesResponse(BaseModel): """Response for JSON-RPC method getLedgerEntries. - See `getLedgerEntries documentation `__ for + See `getLedgerEntries documentation `__ for more information.""" entries: Optional[List[LedgerEntryResult]] = None @@ -126,7 +126,7 @@ class GetLedgerEntriesResponse(BaseModel): class GetNetworkResponse(BaseModel): """Response for JSON-RPC method getNetwork. - See `getNetwork documentation `__ for + See `getNetwork documentation `__ for more information.""" friendbot_url: Optional[str] = Field(alias="friendbotUrl", default=None) @@ -138,7 +138,7 @@ class GetNetworkResponse(BaseModel): class GetHealthResponse(BaseModel): """Response for JSON-RPC method getHealth. - See `getHealth documentation `__ for + See `getHealth documentation `__ for more information. """ @@ -165,7 +165,7 @@ class SimulateTransactionRequest(BaseModel): simulation response for invoke host function, could be one of three types: error, success, or restore operation needed. - See `simulateTransaction documentation `__ for + See `simulateTransaction documentation `__ for more information. """ @@ -216,7 +216,7 @@ class LedgerEntryChange(BaseModel): class SimulateTransactionResponse(BaseModel): """Response for JSON-RPC method simulateTransaction. - See `simulateTransaction documentation `__ for + See `simulateTransaction documentation `__ for more information.""" error: Optional[str] = None @@ -261,7 +261,7 @@ class TransactionResponseError(BaseModel): class GetTransactionRequest(BaseModel): """Response for JSON-RPC method getTransaction. - See `getTransaction documentation `__ for + See `getTransaction documentation `__ for more information.""" hash: str @@ -270,7 +270,7 @@ class GetTransactionRequest(BaseModel): class GetTransactionResponse(BaseModel): """Response for JSON-RPC method getTransaction. - See `getTransaction documentation `__ for + See `getTransaction documentation `__ for more information.""" status: GetTransactionStatus @@ -309,7 +309,7 @@ class SendTransactionStatus(Enum): class SendTransactionRequest(BaseModel): """Response for JSON-RPC method sendTransaction. - See `sendTransaction documentation `__ for + See `sendTransaction documentation `__ for more information.""" transaction: str @@ -318,7 +318,7 @@ class SendTransactionRequest(BaseModel): class SendTransactionResponse(BaseModel): """Response for JSON-RPC method sendTransaction. - See `sendTransaction documentation `__ for + See `sendTransaction documentation `__ for more information.""" error_result_xdr: Optional[str] = Field(alias="errorResultXdr", default=None) @@ -335,9 +335,95 @@ class SendTransactionResponse(BaseModel): class GetLatestLedgerResponse(BaseModel): """Response for JSON-RPC method getLatestLedger. - See `getLatestLedger documentation `__ for + See `getLatestLedger documentation `__ for more information.""" id: str protocol_version: int = Field(alias="protocolVersion") sequence: int + + +# get_fee_stats +class FeeDistribution(BaseModel): + max: int + min: int + mode: int + p10: int + p20: int + p30: int + p40: int + p50: int + p60: int + p70: int + p80: int + p90: int + p95: int + p99: int + transaction_count: int = Field(alias="transactionCount") + ledger_count: int = Field(alias="ledgerCount") + + +class GetFeeStatsResponse(BaseModel): + """Response for JSON-RPC method getFeeStats. + + See `getFeeStats documentation `__ for + more information.""" + + soroban_inclusion_fee: FeeDistribution = Field(alias="sorobanInclusionFee") + inclusion_fee: FeeDistribution = Field(alias="inclusionFee") + latest_ledger: int = Field(alias="latestLedger") + + +# get_transactions +class GetTransactionsRequest(BaseModel): + """Request for JSON-RPC method getTransactions. + + See `getTransactions documentation `__ for + more information.""" + + start_ledger: int = Field(alias="startLedger") + pagination: Optional[PaginationOptions] = None + + +class Transaction(BaseModel): + status: str + application_order: int = Field(alias="applicationOrder") + fee_bump: bool = Field(alias="feeBump") + envelope_xdr: str = Field(alias="envelopeXdr") + result_xdr: str = Field(alias="resultXdr") + result_meta_xdr: str = Field(alias="resultMetaXdr") + ledger: int + created_at: int = Field(alias="createdAt") + diagnostic_events_xdr: Optional[List[str]] = Field( + alias="diagnosticEventsXdr", default=None + ) + + +class GetTransactionsResponse(BaseModel): + """Response for JSON-RPC method getTransactions. + + See `getTransactions documentation `__ for + more information.""" + + transactions: List[Transaction] + latest_ledger: int = Field(alias="latestLedger") + latest_ledger_close_timestamp: int = Field(alias="latestLedgerCloseTimestamp") + oldest_ledger: int = Field(alias="oldestLedger") + oldest_ledger_close_timestamp: int = Field(alias="oldestLedgerCloseTimestamp") + cursor: str + + +# get_version_info +# TODO: To avoid breaking change, let's add it later. +# See: https://github.com/stellar/soroban-rpc/pull/164 +# class GetVersionInfoResponse(BaseModel): +# """Response for JSON-RPC method getVersionInfo. +# +# See `getVersionInfo documentation `__ for +# more information.""" +# +# version: str +# commit_hash: str = Field(alias="commitHash") +# build_time_stamp: str = Field(alias="buildTimeStamp") +# captive_core_version: str = Field(alias="captiveCoreVersion") +# protocol_version: int = Field(alias="protocolVersion") diff --git a/stellar_sdk/soroban_server.py b/stellar_sdk/soroban_server.py index 607d9cf0..9dceb2fa 100644 --- a/stellar_sdk/soroban_server.py +++ b/stellar_sdk/soroban_server.py @@ -53,7 +53,7 @@ def __init__( def get_health(self) -> GetHealthResponse: """General node health check. - See `Soroban Documentation - getHealth `_ + See `Soroban RPC Documentation - getHealth `_ :return: A :class:`GetHealthResponse ` object. :raises: :exc:`SorobanRpcErrorResponse ` - If the Soroban-RPC instance returns an error response. @@ -74,7 +74,7 @@ def get_events( ) -> GetEventsResponse: """Fetch a list of events that occurred in the ledger range. - See `Soroban Documentation - getEvents `_ + See `Soroban RPC Documentation - getEvents `_ :param start_ledger: The first ledger to include in the results. :param filters: A list of filters to apply to the results. @@ -97,6 +97,8 @@ def get_events( def get_network(self) -> GetNetworkResponse: """General info about the currently configured network. + See `Soroban RPC Documentation - getNetwork `_ + :return: A :class:`GetNetworkResponse ` object. :raises: :exc:`SorobanRpcErrorResponse ` - If the Soroban-RPC instance returns an error response. """ @@ -110,6 +112,8 @@ def get_network(self) -> GetNetworkResponse: def get_latest_ledger(self) -> GetLatestLedgerResponse: """Fetches the latest ledger meta info from network which Soroban-RPC is connected to. + See `Soroban RPC Documentation - getLatestLedger `_ + :return: A :class:`GetLatestLedgerResponse ` object. :raises: :exc:`SorobanRpcErrorResponse ` - If the Soroban-RPC instance returns an error response. """ @@ -129,7 +133,7 @@ def get_ledger_entries( or any other ledger entry. This is a backup way to access your contract data which may not be available via events or simulateTransaction. - See `Soroban Documentation - getLedgerEntries `_ + See `Soroban RPC Documentation - getLedgerEntries `_ :param keys: The ledger keys to fetch. :return: A :class:`GetLedgerEntriesResponse ` object. @@ -145,7 +149,7 @@ def get_ledger_entries( def get_transaction(self, transaction_hash: str) -> GetTransactionResponse: """Fetch the specified transaction. - See `Soroban Documentation - getTransaction `_ + See `Soroban RPC Documentation - getTransaction `_ :param transaction_hash: The hash of the transaction to fetch. :return: A :class:`GetTransactionResponse ` object. @@ -165,7 +169,7 @@ def simulate_transaction( ) -> SimulateTransactionResponse: """Submit a trial contract invocation to get back return values, expected ledger footprint, and expected costs. - See `Soroban Documentation - simulateTransaction `_ + See `Soroban RPC Documentation - simulateTransaction `_ :param transaction_envelope: The transaction to simulate. It should include exactly one operation, which must be one of :class:`RestoreFootprint `, @@ -204,7 +208,7 @@ def send_transaction( ) -> SendTransactionResponse: """Submit a real transaction to the Stellar network. This is the only way to make changes "on-chain". - See `Soroban Documentation - sendTransaction `_ + See `Soroban RPC Documentation - sendTransaction `_ :param transaction_envelope: The transaction to send. :return: A :class:`SendTransactionResponse ` object. @@ -222,6 +226,48 @@ def send_transaction( ) return self._post(request, SendTransactionResponse) + def get_fee_stats(self) -> GetFeeStatsResponse: + """General info about the fee stats. + + See `Soroban RPC Documentation - getFeeStats `_ + + :return: A :class:`GetFeeStatsResponse ` object. + :raises: :exc:`SorobanRpcErrorResponse ` - If the Soroban-RPC instance returns an error response. + """ + request: Request = Request( + id=_generate_unique_request_id(), + method="getFeeStats", + params=None, + ) + return self._post(request, GetFeeStatsResponse) + + def get_transactions( + self, + start_ledger: int, + cursor: str = None, + limit: int = None, + ) -> GetTransactionsResponse: + """Fetch a detailed list of transactions starting from the user specified starting point that you can paginate + as long as the pages fall within the history retention of their corresponding RPC provider. + + See `Soroban RPC Documentation - getTransactions `_ + + :param start_ledger: The first ledger to include in the results. + :param cursor: A cursor value for use in pagination. + :param limit: The maximum number of records to return. + :return: A :class:`GetTransactionsResponse ` object. + :raises: :exc:`SorobanRpcErrorResponse ` - If the Soroban-RPC instance returns an error response. + """ + pagination = PaginationOptions(cursor=cursor, limit=limit) + data = GetTransactionsRequest( + startLedger=str(start_ledger), + pagination=pagination, + ) + request: Request = Request[GetTransactionsRequest]( + id=_generate_unique_request_id(), method="getTransactions", params=data + ) + return self._post(request, GetTransactionsResponse) + def load_account(self, account_id: str) -> Account: """Load an account from the server, you can use the returned account object as source account for transactions. diff --git a/stellar_sdk/soroban_server_async.py b/stellar_sdk/soroban_server_async.py index 0d7ccfc0..77efae11 100644 --- a/stellar_sdk/soroban_server_async.py +++ b/stellar_sdk/soroban_server_async.py @@ -53,7 +53,7 @@ def __init__( async def get_health(self) -> GetHealthResponse: """General node health check. - See `Soroban Documentation - getHealth `_ + See `Soroban RPC Documentation - getHealth `_ :return: A :class:`GetHealthResponse ` object. :raises: :exc:`SorobanRpcErrorResponse ` - If the Soroban-RPC instance returns an error response. @@ -74,7 +74,7 @@ async def get_events( ) -> GetEventsResponse: """Fetch a list of events that occurred in the ledger range. - See `Soroban Documentation - getEvents `_ + See `Soroban RPC Documentation - getEvents `_ :param start_ledger: The first ledger to include in the results. :param filters: A list of filters to apply to the results. @@ -97,6 +97,8 @@ async def get_events( async def get_network(self) -> GetNetworkResponse: """General info about the currently configured network. + See `Soroban RPC Documentation - getNetwork `_ + :return: A :class:`GetNetworkResponse ` object. :raises: :exc:`SorobanRpcErrorResponse ` - If the Soroban-RPC instance returns an error response. """ @@ -110,6 +112,8 @@ async def get_network(self) -> GetNetworkResponse: async def get_latest_ledger(self) -> GetLatestLedgerResponse: """Fetches the latest ledger meta info from network which Soroban-RPC is connected to. + See `Soroban RPC Documentation - getLatestLedger `_ + :return: A :class:`GetLatestLedgerResponse ` object. :raises: :exc:`SorobanRpcErrorResponse ` - If the Soroban-RPC instance returns an error response. """ @@ -129,7 +133,7 @@ async def get_ledger_entries( or any other ledger entry. This is a backup way to access your contract data which may not be available via events or simulateTransaction. - See `Soroban Documentation - getLedgerEntries `_ + See `Soroban RPC Documentation - getLedgerEntries `_ :param keys: The ledger keys to fetch. :return: A :class:`GetLedgerEntriesResponse ` object. @@ -145,7 +149,7 @@ async def get_ledger_entries( async def get_transaction(self, transaction_hash: str) -> GetTransactionResponse: """Fetch the specified transaction. - See `Soroban Documentation - getTransaction `_ + See `Soroban RPC Documentation - getTransaction `_ :param transaction_hash: The hash of the transaction to fetch. :return: A :class:`GetTransactionResponse ` object. @@ -165,7 +169,7 @@ async def simulate_transaction( ) -> SimulateTransactionResponse: """Submit a trial contract invocation to get back return values, expected ledger footprint, and expected costs. - See `Soroban Documentation - simulateTransaction `_ + See `Soroban RPC Documentation - simulateTransaction `_ :param transaction_envelope: The transaction to simulate. It should include exactly one operation, which must be one of :class:`RestoreFootprint `, @@ -203,7 +207,7 @@ async def send_transaction( ) -> SendTransactionResponse: """Submit a real transaction to the Stellar network. This is the only way to make changes "on-chain". - See `Soroban Documentation - sendTransaction `_ + See `Soroban RPC Documentation - sendTransaction `_ :param transaction_envelope: The transaction to send. :return: A :class:`SendTransactionResponse ` object. @@ -221,6 +225,48 @@ async def send_transaction( ) return await self._post(request, SendTransactionResponse) + async def get_fee_stats(self) -> GetFeeStatsResponse: + """General info about the fee stats. + + See `Soroban RPC Documentation - getFeeStats `_ + + :return: A :class:`GetFeeStatsResponse ` object. + :raises: :exc:`SorobanRpcErrorResponse ` - If the Soroban-RPC instance returns an error response. + """ + request: Request = Request( + id=_generate_unique_request_id(), + method="getFeeStats", + params=None, + ) + return await self._post(request, GetFeeStatsResponse) + + async def get_transactions( + self, + start_ledger: int, + cursor: str = None, + limit: int = None, + ) -> GetTransactionsResponse: + """Fetch a detailed list of transactions starting from the user specified starting point that you can paginate + as long as the pages fall within the history retention of their corresponding RPC provider. + + See `Soroban RPC Documentation - getTransactions `_ + + :param start_ledger: The first ledger to include in the results. + :param cursor: A cursor value for use in pagination. + :param limit: The maximum number of records to return. + :return: A :class:`GetTransactionsResponse ` object. + :raises: :exc:`SorobanRpcErrorResponse ` - If the Soroban-RPC instance returns an error response. + """ + pagination = PaginationOptions(cursor=cursor, limit=limit) + data = GetTransactionsRequest( + startLedger=str(start_ledger), + pagination=pagination, + ) + request: Request = Request[GetTransactionsRequest]( + id=_generate_unique_request_id(), method="getTransactions", params=data + ) + return await self._post(request, GetTransactionsResponse) + async def load_account(self, account_id: str) -> Account: """Load an account from the server, you can use the returned account object as source account for transactions. diff --git a/tests/test_soroban_server_async.py b/tests/test_soroban_server_async.py index 61123c51..7ed04fb0 100644 --- a/tests/test_soroban_server_async.py +++ b/tests/test_soroban_server_async.py @@ -390,6 +390,172 @@ async def test_get_latest_ledger(self): assert request_data["method"] == "getLatestLedger" assert request_data["params"] is None + async def test_get_fee_stats(self): + result = { + "sorobanInclusionFee": { + "max": "210", + "min": "100", + "mode": "100", + "p10": "100", + "p20": "100", + "p30": "100", + "p40": "100", + "p50": "100", + "p60": "100", + "p70": "100", + "p80": "100", + "p90": "120", + "p95": "190", + "p99": "200", + "transactionCount": "10", + "ledgerCount": 50, + }, + "inclusionFee": { + "max": "100", + "min": "100", + "mode": "100", + "p10": "100", + "p20": "100", + "p30": "100", + "p40": "100", + "p50": "100", + "p60": "100", + "p70": "100", + "p80": "100", + "p90": "100", + "p95": "100", + "p99": "100", + "transactionCount": "7", + "ledgerCount": 10, + }, + "latestLedger": 4519945, + } + + data = { + "jsonrpc": "2.0", + "id": "198cb1a8-9104-4446-a269-88bf000c2721", + "result": result, + } + with aioresponses() as m: + m.post(PRC_URL, payload=data) + async with SorobanServerAsync(PRC_URL) as client: + assert ( + await client.get_fee_stats() + ) == GetFeeStatsResponse.model_validate(result) + + request_data = m.requests[("POST", URL(PRC_URL))][0].kwargs["json"] + assert len(request_data["id"]) == 32 + assert request_data["jsonrpc"] == "2.0" + assert request_data["method"] == "getFeeStats" + assert request_data["params"] is None + + async def test_get_transactions(self): + result = { + "transactions": [ + { + "status": "FAILED", + "applicationOrder": 1, + "feeBump": False, + "envelopeXdr": "AAAAAgAAAACDz21Q3CTITlGqRus3/96/05EDivbtfJncNQKt64BTbAAAASwAAKkyAAXlMwAAAAEAAAAAAAAAAAAAAABmWeASAAAAAQAAABR3YWxsZXQ6MTcxMjkwNjMzNjUxMAAAAAEAAAABAAAAAIPPbVDcJMhOUapG6zf/3r/TkQOK9u18mdw1Aq3rgFNsAAAAAQAAAABwOSvou8mtwTtCkysVioO35TSgyRir2+WGqO8FShG/GAAAAAFVQUgAAAAAAO371tlrHUfK+AvmQvHje1jSUrvJb3y3wrJ7EplQeqTkAAAAAAX14QAAAAAAAAAAAeuAU2wAAABAn+6A+xXvMasptAm9BEJwf5Y9CLLQtV44TsNqS8ocPmn4n8Rtyb09SBiFoMv8isYgeQU5nAHsIwBNbEKCerusAQ==", + "resultXdr": "AAAAAAAAAGT/////AAAAAQAAAAAAAAAB////+gAAAAA=", + "resultMetaXdr": "AAAAAwAAAAAAAAACAAAAAwAc0RsAAAAAAAAAAIPPbVDcJMhOUapG6zf/3r/TkQOK9u18mdw1Aq3rgFNsAAAAF0YpYBQAAKkyAAXlMgAAAAsAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAMAAAAAABzRGgAAAABmWd/VAAAAAAAAAAEAHNEbAAAAAAAAAACDz21Q3CTITlGqRus3/96/05EDivbtfJncNQKt64BTbAAAABdGKWAUAACpMgAF5TMAAAALAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAAAc0RsAAAAAZlnf2gAAAAAAAAAAAAAAAAAAAAA=", + "ledger": 1888539, + "createdAt": 1717166042, + }, + { + "status": "SUCCESS", + "applicationOrder": 2, + "feeBump": False, + "envelopeXdr": "AAAAAgAAAAC4EZup+ewCs/doS3hKbeAa4EviBHqAFYM09oHuLtqrGAAPQkAAGgQZAAAANgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAABB90WssODNIgi6BHveqzxTRmIpvAFRyVNM+Hm2GVuCcAAAAAAAAAAAq6aHAHZ2sd9aPbRsskrlXMLWIwqs4Sv2Bk+VwuIR+9wAAABdIdugAAAAAAAAAAAIu2qsYAAAAQERzKOqYYiPXNwsiL8ADAG/f45RBssmf3umGzw4qKkLGlObuPdX0buWmTGrhI13SG38F2V8Mp9DI+eDkcCjMSAOGVuCcAAAAQHnm0o/r+Gsl+6oqBgSbqoSY37gflvQB3zZRghuir0N75UVerd0Q50yG5Zfu08i2crhx6uk+5HYTl8/Sa7uZ+Qc=", + "resultXdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAA=", + "resultMetaXdr": "AAAAAwAAAAAAAAACAAAAAwAc0RsAAAAAAAAAALgRm6n57AKz92hLeEpt4BrgS+IEeoAVgzT2ge4u2qsYAAAAADwzS2gAGgQZAAAANQAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAMAAAAAABzPVAAAAABmWdZ2AAAAAAAAAAEAHNEbAAAAAAAAAAC4EZup+ewCs/doS3hKbeAa4EviBHqAFYM09oHuLtqrGAAAAAA8M0toABoEGQAAADYAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAAAc0RsAAAAAZlnf2gAAAAAAAAABAAAAAwAAAAMAHNEaAAAAAAAAAAAQfdFrLDgzSIIugR73qs8U0ZiKbwBUclTTPh5thlbgnABZJUSd0V2hAAAAawAAAlEAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAAAaBGEAAAAAZkspCwAAAAAAAAABABzRGwAAAAAAAAAAEH3Rayw4M0iCLoEe96rPFNGYim8AVHJU0z4ebYZW4JwAWSUtVVp1oQAAAGsAAAJRAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAwAAAAAAGgRhAAAAAGZLKQsAAAAAAAAAAAAc0RsAAAAAAAAAACrpocAdnax31o9tGyySuVcwtYjCqzhK/YGT5XC4hH73AAAAF0h26AAAHNEbAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + "ledger": 1888539, + "createdAt": 1717166042, + }, + { + "status": "SUCCESS", + "applicationOrder": 3, + "feeBump": False, + "envelopeXdr": "AAAAAgAAAACwtG/IRC5DZE1UdekijEsoQEPM/uOwZ3iY/Y8UZ3b9xAAPQkAAGgRHAAAANgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAABB90WssODNIgi6BHveqzxTRmIpvAFRyVNM+Hm2GVuCcAAAAAAAAAADgdupKeB04lazKXCOb+E1JfxaM3tI4Xsb/qDa1MWOvXgAAABdIdugAAAAAAAAAAAJndv3EAAAAQKcTimw6KKcM0AeCMxXJcEK/hS9ROoj/qpMFppGNAr4W3ifSOSTGAFbA+cIVHmaV4p7xGcR+9JnUN1YjamvJZwSGVuCcAAAAQK9Cp775JbnYA793SXkkWWbmvnEFTiDPiFyTHxTphCwBDB1zqkXqGG6Q5O3dAyqkNJvj1XNRDsmY4pKV41qijQU=", + "resultXdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAA=", + "resultMetaXdr": "AAAAAwAAAAAAAAACAAAAAwAc0RsAAAAAAAAAALC0b8hELkNkTVR16SKMSyhAQ8z+47BneJj9jxRndv3EAAAAADwzS2gAGgRHAAAANQAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAMAAAAAABzPVAAAAABmWdZ2AAAAAAAAAAEAHNEbAAAAAAAAAACwtG/IRC5DZE1UdekijEsoQEPM/uOwZ3iY/Y8UZ3b9xAAAAAA8M0toABoERwAAADYAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAAAc0RsAAAAAZlnf2gAAAAAAAAABAAAAAwAAAAMAHNEbAAAAAAAAAAAQfdFrLDgzSIIugR73qs8U0ZiKbwBUclTTPh5thlbgnABZJS1VWnWhAAAAawAAAlEAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAAAaBGEAAAAAZkspCwAAAAAAAAABABzRGwAAAAAAAAAAEH3Rayw4M0iCLoEe96rPFNGYim8AVHJU0z4ebYZW4JwAWSUWDOONoQAAAGsAAAJRAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAwAAAAAAGgRhAAAAAGZLKQsAAAAAAAAAAAAc0RsAAAAAAAAAAOB26kp4HTiVrMpcI5v4TUl/Foze0jhexv+oNrUxY69eAAAAF0h26AAAHNEbAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + "ledger": 1888539, + "createdAt": 1717166042, + }, + { + "status": "SUCCESS", + "applicationOrder": 4, + "feeBump": False, + "envelopeXdr": "AAAAAgAAAACxMt2gKYOehEoVbmh9vfvZ4mVzXFSNTbAU5S4a8zorrAA4wrwAHLqRAAAADAAAAAAAAAAAAAAAAQAAAAAAAAAYAAAAAQAAAAAAAAAAAAAAALEy3aApg56EShVuaH29+9niZXNcVI1NsBTlLhrzOiusz3K+BVgRzXig/Bhz1TL5Qy+Ibv6cDvCfdaAtBMMFPcYAAAAAHXUVmJM11pdJSKKV52UJrVYlvxaPLmmg17nMe0HGy0MAAAABAAAAAAAAAAEAAAAAAAAAAAAAAACxMt2gKYOehEoVbmh9vfvZ4mVzXFSNTbAU5S4a8zorrM9yvgVYEc14oPwYc9Uy+UMviG7+nA7wn3WgLQTDBT3GAAAAAB11FZiTNdaXSUiiledlCa1WJb8Wjy5poNe5zHtBxstDAAAAAAAAAAEAAAAAAAAAAQAAAAcddRWYkzXWl0lIopXnZQmtViW/Fo8uaaDXucx7QcbLQwAAAAEAAAAGAAAAAbolCtTsMrJvK0M2SaskFsaMajj3iAZbXxELZHwDyE5dAAAAFAAAAAEABf2jAAAd1AAAAGgAAAAAADjCWAAAAAHzOiusAAAAQM+qaiMKxMoCVNjdRIh3X9CSxkjAm0BpXYDB9Fd+DS0guYKiY3TMaVe243UB008iBn5ynQv724rReXlg7iFqXQA=", + "resultXdr": "AAAAAAAw3cUAAAAAAAAAAQAAAAAAAAAYAAAAAKg/pGuhtOG27rIpG8xhUIp46CStGWOcsGlNsTQv44UOAAAAAA==", + "resultMetaXdr": "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", + "diagnosticEventsXdr": [ + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAACnJlYWRfZW50cnkAAAAAAAUAAAAAAAAAAg==", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAC3dyaXRlX2VudHJ5AAAAAAUAAAAAAAAAAQ==", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAEGxlZGdlcl9yZWFkX2J5dGUAAAAFAAAAAAAAHdQ=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAEWxlZGdlcl93cml0ZV9ieXRlAAAAAAAABQAAAAAAAABo", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAADXJlYWRfa2V5X2J5dGUAAAAAAAAFAAAAAAAAAFQ=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAADndyaXRlX2tleV9ieXRlAAAAAAAFAAAAAAAAAAA=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAADnJlYWRfZGF0YV9ieXRlAAAAAAAFAAAAAAAAAAA=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAD3dyaXRlX2RhdGFfYnl0ZQAAAAAFAAAAAAAAAGg=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAADnJlYWRfY29kZV9ieXRlAAAAAAAFAAAAAAAAHdQ=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAD3dyaXRlX2NvZGVfYnl0ZQAAAAAFAAAAAAAAAAA=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAACmVtaXRfZXZlbnQAAAAAAAUAAAAAAAAAAA==", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAD2VtaXRfZXZlbnRfYnl0ZQAAAAAFAAAAAAAAAAA=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAACGNwdV9pbnNuAAAABQAAAAAABTO4", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAACG1lbV9ieXRlAAAABQAAAAAAAPkD", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAEWludm9rZV90aW1lX25zZWNzAAAAAAAABQAAAAAAAmiz", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAD21heF9yd19rZXlfYnl0ZQAAAAAFAAAAAAAAADA=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAEG1heF9yd19kYXRhX2J5dGUAAAAFAAAAAAAAAGg=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAEG1heF9yd19jb2RlX2J5dGUAAAAFAAAAAAAAHdQ=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAE21heF9lbWl0X2V2ZW50X2J5dGUAAAAABQAAAAAAAAAA", + ], + "ledger": 1888539, + "createdAt": 1717166042, + }, + { + "status": "FAILED", + "applicationOrder": 1, + "feeBump": False, + "envelopeXdr": "AAAAAgAAAAAxLMEcxmfUgNzL687Js4sX/jmFQDqTo1Lj4KDoC1PeSQAehIAAAAIJAAtMUQAAAAEAAAAAAAAAAAAAAABmWeAVAAAAAQAAAAlwc3BiOjMyMTcAAAAAAAACAAAAAQAAAACKlutUN5GT3UOoE2BUkNtJEwoipGOinBFsQtXgpIZMxQAAAAEAAAAA433o+yremWU3t88cKpfpHR+JMFR44JHzmBGni6hqCEYAAAACQVRVQUgAAAAAAAAAAAAAAGfK1mN4mg51jbX6by6TWghGynQ463doEDgzriqZo9bzAAAAAAaOd4AAAAABAAAAAIqW61Q3kZPdQ6gTYFSQ20kTCiKkY6KcEWxC1eCkhkzFAAAAAQAAAADjfej7Kt6ZZTe3zxwql+kdH4kwVHjgkfOYEaeLqGoIRgAAAAJBVFVTRAAAAAAAAAAAAAAAZ8rWY3iaDnWNtfpvLpNaCEbKdDjrd2gQODOuKpmj1vMAAAAAADh1IAAAAAAAAAACC1PeSQAAAEBoad/kqj/4Sqq5tC6HyeMm5LJKM1VqKRGZc3e4uvA3ITThwn2nNMRJRegdQrLrPBTSgw51nY8npilXVIds7I0OpIZMxQAAAEDTZNaLjIDMWPDdCxa1ZB28vUxTcS/0xykOFTI/JAz096vX6Y7wI0QvnbPM7KCoL0cJAciD+pJxNqXQ2Aff1hoO", + "resultXdr": "AAAAAAAAAMj/////AAAAAgAAAAAAAAAB////+wAAAAAAAAAB////+wAAAAA=", + "resultMetaXdr": "AAAAAwAAAAAAAAACAAAAAwAc0RwAAAAAAAAAADEswRzGZ9SA3Mvrzsmzixf+OYVAOpOjUuPgoOgLU95JAAAAFxzxIbUAAAIJAAtMUAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAMAAAAAABzRGgAAAABmWd/VAAAAAAAAAAEAHNEcAAAAAAAAAAAxLMEcxmfUgNzL687Js4sX/jmFQDqTo1Lj4KDoC1PeSQAAABcc8SG1AAACCQALTFEAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAAAc0RwAAAAAZlnf3wAAAAAAAAAAAAAAAAAAAAA=", + "ledger": 1888540, + "createdAt": 1717166047, + }, + ], + "latestLedger": 1888542, + "latestLedgerCloseTimestamp": 1717166057, + "oldestLedger": 1871263, + "oldestLedgerCloseTimestamp": 1717075350, + "cursor": "8111217537191937", + } + + data = { + "jsonrpc": "2.0", + "id": "198cb1a8-9104-4446-a269-88bf000c2721", + "result": result, + } + + start_ledger = 1888539 + GetTransactionsResponse.model_validate(result) + limit = 5 + with aioresponses() as m: + m.post(PRC_URL, payload=data) + async with SorobanServerAsync(PRC_URL) as client: + assert ( + await client.get_transactions(start_ledger, None, limit) + ) == GetTransactionsResponse.model_validate(result) + + request_data = m.requests[("POST", URL(PRC_URL))][0].kwargs["json"] + assert len(request_data["id"]) == 32 + assert request_data["jsonrpc"] == "2.0" + assert request_data["method"] == "getTransactions" + assert request_data["params"] == { + "startLedger": 1888539, + "pagination": {"cursor": None, "limit": 5}, + } + async def test_simulate_transaction(self): result = { "transactionData": "AAAAAAAAAAIAAAAGAAAAAcWLK/vE8FTnMk9r8gytPgJuQbutGm0gw9fUkY3tFlQRAAAAFAAAAAEAAAAAAAAAB300Hyg0HZG+Qie3zvsxLvugrNtFqd3AIntWy9bg2YvZAAAAAAAAAAEAAAAGAAAAAcWLK/vE8FTnMk9r8gytPgJuQbutGm0gw9fUkY3tFlQRAAAAEAAAAAEAAAACAAAADwAAAAdDb3VudGVyAAAAABIAAAAAAAAAAFi3xKLI8peqjz0kcSgf38zsr+SOVmMxPsGOEqc+ypihAAAAAQAAAAAAFcLDAAAF8AAAAQgAAAMcAAAAAAAAAJw=", diff --git a/tests/test_soroban_server_sync.py b/tests/test_soroban_server_sync.py index 07abc3b9..b99bf6ee 100644 --- a/tests/test_soroban_server_sync.py +++ b/tests/test_soroban_server_sync.py @@ -380,6 +380,170 @@ def test_get_latest_ledger(self): assert request_data["method"] == "getLatestLedger" assert request_data["params"] is None + def test_get_fee_stats(self): + result = { + "sorobanInclusionFee": { + "max": "210", + "min": "100", + "mode": "100", + "p10": "100", + "p20": "100", + "p30": "100", + "p40": "100", + "p50": "100", + "p60": "100", + "p70": "100", + "p80": "100", + "p90": "120", + "p95": "190", + "p99": "200", + "transactionCount": "10", + "ledgerCount": 50, + }, + "inclusionFee": { + "max": "100", + "min": "100", + "mode": "100", + "p10": "100", + "p20": "100", + "p30": "100", + "p40": "100", + "p50": "100", + "p60": "100", + "p70": "100", + "p80": "100", + "p90": "100", + "p95": "100", + "p99": "100", + "transactionCount": "7", + "ledgerCount": 10, + }, + "latestLedger": 4519945, + } + + data = { + "jsonrpc": "2.0", + "id": "198cb1a8-9104-4446-a269-88bf000c2721", + "result": result, + } + with requests_mock.Mocker() as m: + m.post(PRC_URL, json=data) + assert SorobanServer( + PRC_URL + ).get_fee_stats() == GetFeeStatsResponse.model_validate(result) + + request_data = m.last_request.json() + assert len(request_data["id"]) == 32 + assert request_data["jsonrpc"] == "2.0" + assert request_data["method"] == "getFeeStats" + assert request_data["params"] is None + + def test_get_transactions(self): + result = { + "transactions": [ + { + "status": "FAILED", + "applicationOrder": 1, + "feeBump": False, + "envelopeXdr": "AAAAAgAAAACDz21Q3CTITlGqRus3/96/05EDivbtfJncNQKt64BTbAAAASwAAKkyAAXlMwAAAAEAAAAAAAAAAAAAAABmWeASAAAAAQAAABR3YWxsZXQ6MTcxMjkwNjMzNjUxMAAAAAEAAAABAAAAAIPPbVDcJMhOUapG6zf/3r/TkQOK9u18mdw1Aq3rgFNsAAAAAQAAAABwOSvou8mtwTtCkysVioO35TSgyRir2+WGqO8FShG/GAAAAAFVQUgAAAAAAO371tlrHUfK+AvmQvHje1jSUrvJb3y3wrJ7EplQeqTkAAAAAAX14QAAAAAAAAAAAeuAU2wAAABAn+6A+xXvMasptAm9BEJwf5Y9CLLQtV44TsNqS8ocPmn4n8Rtyb09SBiFoMv8isYgeQU5nAHsIwBNbEKCerusAQ==", + "resultXdr": "AAAAAAAAAGT/////AAAAAQAAAAAAAAAB////+gAAAAA=", + "resultMetaXdr": "AAAAAwAAAAAAAAACAAAAAwAc0RsAAAAAAAAAAIPPbVDcJMhOUapG6zf/3r/TkQOK9u18mdw1Aq3rgFNsAAAAF0YpYBQAAKkyAAXlMgAAAAsAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAMAAAAAABzRGgAAAABmWd/VAAAAAAAAAAEAHNEbAAAAAAAAAACDz21Q3CTITlGqRus3/96/05EDivbtfJncNQKt64BTbAAAABdGKWAUAACpMgAF5TMAAAALAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAAAc0RsAAAAAZlnf2gAAAAAAAAAAAAAAAAAAAAA=", + "ledger": 1888539, + "createdAt": 1717166042, + }, + { + "status": "SUCCESS", + "applicationOrder": 2, + "feeBump": False, + "envelopeXdr": "AAAAAgAAAAC4EZup+ewCs/doS3hKbeAa4EviBHqAFYM09oHuLtqrGAAPQkAAGgQZAAAANgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAABB90WssODNIgi6BHveqzxTRmIpvAFRyVNM+Hm2GVuCcAAAAAAAAAAAq6aHAHZ2sd9aPbRsskrlXMLWIwqs4Sv2Bk+VwuIR+9wAAABdIdugAAAAAAAAAAAIu2qsYAAAAQERzKOqYYiPXNwsiL8ADAG/f45RBssmf3umGzw4qKkLGlObuPdX0buWmTGrhI13SG38F2V8Mp9DI+eDkcCjMSAOGVuCcAAAAQHnm0o/r+Gsl+6oqBgSbqoSY37gflvQB3zZRghuir0N75UVerd0Q50yG5Zfu08i2crhx6uk+5HYTl8/Sa7uZ+Qc=", + "resultXdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAA=", + "resultMetaXdr": "AAAAAwAAAAAAAAACAAAAAwAc0RsAAAAAAAAAALgRm6n57AKz92hLeEpt4BrgS+IEeoAVgzT2ge4u2qsYAAAAADwzS2gAGgQZAAAANQAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAMAAAAAABzPVAAAAABmWdZ2AAAAAAAAAAEAHNEbAAAAAAAAAAC4EZup+ewCs/doS3hKbeAa4EviBHqAFYM09oHuLtqrGAAAAAA8M0toABoEGQAAADYAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAAAc0RsAAAAAZlnf2gAAAAAAAAABAAAAAwAAAAMAHNEaAAAAAAAAAAAQfdFrLDgzSIIugR73qs8U0ZiKbwBUclTTPh5thlbgnABZJUSd0V2hAAAAawAAAlEAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAAAaBGEAAAAAZkspCwAAAAAAAAABABzRGwAAAAAAAAAAEH3Rayw4M0iCLoEe96rPFNGYim8AVHJU0z4ebYZW4JwAWSUtVVp1oQAAAGsAAAJRAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAwAAAAAAGgRhAAAAAGZLKQsAAAAAAAAAAAAc0RsAAAAAAAAAACrpocAdnax31o9tGyySuVcwtYjCqzhK/YGT5XC4hH73AAAAF0h26AAAHNEbAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + "ledger": 1888539, + "createdAt": 1717166042, + }, + { + "status": "SUCCESS", + "applicationOrder": 3, + "feeBump": False, + "envelopeXdr": "AAAAAgAAAACwtG/IRC5DZE1UdekijEsoQEPM/uOwZ3iY/Y8UZ3b9xAAPQkAAGgRHAAAANgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAABB90WssODNIgi6BHveqzxTRmIpvAFRyVNM+Hm2GVuCcAAAAAAAAAADgdupKeB04lazKXCOb+E1JfxaM3tI4Xsb/qDa1MWOvXgAAABdIdugAAAAAAAAAAAJndv3EAAAAQKcTimw6KKcM0AeCMxXJcEK/hS9ROoj/qpMFppGNAr4W3ifSOSTGAFbA+cIVHmaV4p7xGcR+9JnUN1YjamvJZwSGVuCcAAAAQK9Cp775JbnYA793SXkkWWbmvnEFTiDPiFyTHxTphCwBDB1zqkXqGG6Q5O3dAyqkNJvj1XNRDsmY4pKV41qijQU=", + "resultXdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAA=", + "resultMetaXdr": "AAAAAwAAAAAAAAACAAAAAwAc0RsAAAAAAAAAALC0b8hELkNkTVR16SKMSyhAQ8z+47BneJj9jxRndv3EAAAAADwzS2gAGgRHAAAANQAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAMAAAAAABzPVAAAAABmWdZ2AAAAAAAAAAEAHNEbAAAAAAAAAACwtG/IRC5DZE1UdekijEsoQEPM/uOwZ3iY/Y8UZ3b9xAAAAAA8M0toABoERwAAADYAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAAAc0RsAAAAAZlnf2gAAAAAAAAABAAAAAwAAAAMAHNEbAAAAAAAAAAAQfdFrLDgzSIIugR73qs8U0ZiKbwBUclTTPh5thlbgnABZJS1VWnWhAAAAawAAAlEAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAAAaBGEAAAAAZkspCwAAAAAAAAABABzRGwAAAAAAAAAAEH3Rayw4M0iCLoEe96rPFNGYim8AVHJU0z4ebYZW4JwAWSUWDOONoQAAAGsAAAJRAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAwAAAAAAGgRhAAAAAGZLKQsAAAAAAAAAAAAc0RsAAAAAAAAAAOB26kp4HTiVrMpcI5v4TUl/Foze0jhexv+oNrUxY69eAAAAF0h26AAAHNEbAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + "ledger": 1888539, + "createdAt": 1717166042, + }, + { + "status": "SUCCESS", + "applicationOrder": 4, + "feeBump": False, + "envelopeXdr": "AAAAAgAAAACxMt2gKYOehEoVbmh9vfvZ4mVzXFSNTbAU5S4a8zorrAA4wrwAHLqRAAAADAAAAAAAAAAAAAAAAQAAAAAAAAAYAAAAAQAAAAAAAAAAAAAAALEy3aApg56EShVuaH29+9niZXNcVI1NsBTlLhrzOiusz3K+BVgRzXig/Bhz1TL5Qy+Ibv6cDvCfdaAtBMMFPcYAAAAAHXUVmJM11pdJSKKV52UJrVYlvxaPLmmg17nMe0HGy0MAAAABAAAAAAAAAAEAAAAAAAAAAAAAAACxMt2gKYOehEoVbmh9vfvZ4mVzXFSNTbAU5S4a8zorrM9yvgVYEc14oPwYc9Uy+UMviG7+nA7wn3WgLQTDBT3GAAAAAB11FZiTNdaXSUiiledlCa1WJb8Wjy5poNe5zHtBxstDAAAAAAAAAAEAAAAAAAAAAQAAAAcddRWYkzXWl0lIopXnZQmtViW/Fo8uaaDXucx7QcbLQwAAAAEAAAAGAAAAAbolCtTsMrJvK0M2SaskFsaMajj3iAZbXxELZHwDyE5dAAAAFAAAAAEABf2jAAAd1AAAAGgAAAAAADjCWAAAAAHzOiusAAAAQM+qaiMKxMoCVNjdRIh3X9CSxkjAm0BpXYDB9Fd+DS0guYKiY3TMaVe243UB008iBn5ynQv724rReXlg7iFqXQA=", + "resultXdr": "AAAAAAAw3cUAAAAAAAAAAQAAAAAAAAAYAAAAAKg/pGuhtOG27rIpG8xhUIp46CStGWOcsGlNsTQv44UOAAAAAA==", + "resultMetaXdr": "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", + "diagnosticEventsXdr": [ + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAACnJlYWRfZW50cnkAAAAAAAUAAAAAAAAAAg==", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAC3dyaXRlX2VudHJ5AAAAAAUAAAAAAAAAAQ==", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAEGxlZGdlcl9yZWFkX2J5dGUAAAAFAAAAAAAAHdQ=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAEWxlZGdlcl93cml0ZV9ieXRlAAAAAAAABQAAAAAAAABo", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAADXJlYWRfa2V5X2J5dGUAAAAAAAAFAAAAAAAAAFQ=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAADndyaXRlX2tleV9ieXRlAAAAAAAFAAAAAAAAAAA=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAADnJlYWRfZGF0YV9ieXRlAAAAAAAFAAAAAAAAAAA=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAD3dyaXRlX2RhdGFfYnl0ZQAAAAAFAAAAAAAAAGg=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAADnJlYWRfY29kZV9ieXRlAAAAAAAFAAAAAAAAHdQ=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAD3dyaXRlX2NvZGVfYnl0ZQAAAAAFAAAAAAAAAAA=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAACmVtaXRfZXZlbnQAAAAAAAUAAAAAAAAAAA==", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAD2VtaXRfZXZlbnRfYnl0ZQAAAAAFAAAAAAAAAAA=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAACGNwdV9pbnNuAAAABQAAAAAABTO4", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAACG1lbV9ieXRlAAAABQAAAAAAAPkD", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAEWludm9rZV90aW1lX25zZWNzAAAAAAAABQAAAAAAAmiz", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAD21heF9yd19rZXlfYnl0ZQAAAAAFAAAAAAAAADA=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAEG1heF9yd19kYXRhX2J5dGUAAAAFAAAAAAAAAGg=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAEG1heF9yd19jb2RlX2J5dGUAAAAFAAAAAAAAHdQ=", + "AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAADwAAAAxjb3JlX21ldHJpY3MAAAAPAAAAE21heF9lbWl0X2V2ZW50X2J5dGUAAAAABQAAAAAAAAAA", + ], + "ledger": 1888539, + "createdAt": 1717166042, + }, + { + "status": "FAILED", + "applicationOrder": 1, + "feeBump": False, + "envelopeXdr": "AAAAAgAAAAAxLMEcxmfUgNzL687Js4sX/jmFQDqTo1Lj4KDoC1PeSQAehIAAAAIJAAtMUQAAAAEAAAAAAAAAAAAAAABmWeAVAAAAAQAAAAlwc3BiOjMyMTcAAAAAAAACAAAAAQAAAACKlutUN5GT3UOoE2BUkNtJEwoipGOinBFsQtXgpIZMxQAAAAEAAAAA433o+yremWU3t88cKpfpHR+JMFR44JHzmBGni6hqCEYAAAACQVRVQUgAAAAAAAAAAAAAAGfK1mN4mg51jbX6by6TWghGynQ463doEDgzriqZo9bzAAAAAAaOd4AAAAABAAAAAIqW61Q3kZPdQ6gTYFSQ20kTCiKkY6KcEWxC1eCkhkzFAAAAAQAAAADjfej7Kt6ZZTe3zxwql+kdH4kwVHjgkfOYEaeLqGoIRgAAAAJBVFVTRAAAAAAAAAAAAAAAZ8rWY3iaDnWNtfpvLpNaCEbKdDjrd2gQODOuKpmj1vMAAAAAADh1IAAAAAAAAAACC1PeSQAAAEBoad/kqj/4Sqq5tC6HyeMm5LJKM1VqKRGZc3e4uvA3ITThwn2nNMRJRegdQrLrPBTSgw51nY8npilXVIds7I0OpIZMxQAAAEDTZNaLjIDMWPDdCxa1ZB28vUxTcS/0xykOFTI/JAz096vX6Y7wI0QvnbPM7KCoL0cJAciD+pJxNqXQ2Aff1hoO", + "resultXdr": "AAAAAAAAAMj/////AAAAAgAAAAAAAAAB////+wAAAAAAAAAB////+wAAAAA=", + "resultMetaXdr": "AAAAAwAAAAAAAAACAAAAAwAc0RwAAAAAAAAAADEswRzGZ9SA3Mvrzsmzixf+OYVAOpOjUuPgoOgLU95JAAAAFxzxIbUAAAIJAAtMUAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAMAAAAAABzRGgAAAABmWd/VAAAAAAAAAAEAHNEcAAAAAAAAAAAxLMEcxmfUgNzL687Js4sX/jmFQDqTo1Lj4KDoC1PeSQAAABcc8SG1AAACCQALTFEAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAAAc0RwAAAAAZlnf3wAAAAAAAAAAAAAAAAAAAAA=", + "ledger": 1888540, + "createdAt": 1717166047, + }, + ], + "latestLedger": 1888542, + "latestLedgerCloseTimestamp": 1717166057, + "oldestLedger": 1871263, + "oldestLedgerCloseTimestamp": 1717075350, + "cursor": "8111217537191937", + } + + data = { + "jsonrpc": "2.0", + "id": "198cb1a8-9104-4446-a269-88bf000c2721", + "result": result, + } + + start_ledger = 1888539 + GetTransactionsResponse.model_validate(result) + limit = 5 + with requests_mock.Mocker() as m: + m.post(PRC_URL, json=data) + assert SorobanServer(PRC_URL).get_transactions( + start_ledger, None, limit + ) == GetTransactionsResponse.model_validate(result) + + request_data = m.last_request.json() + assert len(request_data["id"]) == 32 + assert request_data["jsonrpc"] == "2.0" + assert request_data["method"] == "getTransactions" + assert request_data["params"] == { + "startLedger": 1888539, + "pagination": {"cursor": None, "limit": 5}, + } + def test_simulate_transaction(self): result = { "transactionData": "AAAAAAAAAAIAAAAGAAAAAcWLK/vE8FTnMk9r8gytPgJuQbutGm0gw9fUkY3tFlQRAAAAFAAAAAEAAAAAAAAAB300Hyg0HZG+Qie3zvsxLvugrNtFqd3AIntWy9bg2YvZAAAAAAAAAAEAAAAGAAAAAcWLK/vE8FTnMk9r8gytPgJuQbutGm0gw9fUkY3tFlQRAAAAEAAAAAEAAAACAAAADwAAAAdDb3VudGVyAAAAABIAAAAAAAAAAFi3xKLI8peqjz0kcSgf38zsr+SOVmMxPsGOEqc+ypihAAAAAQAAAAAAFcLDAAAF8AAAAQgAAAMcAAAAAAAAAJw=",