From a385a6146e813b94c458dfb4a88c610e3dc5f083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sa=C5=82aban?= Date: Tue, 27 Sep 2022 21:20:44 +0200 Subject: [PATCH] Add address_balance method --- monero/account.py | 20 ++ monero/backends/jsonrpc/wallet.py | 19 ++ monero/wallet.py | 16 +- .../test_address_balance-00-get_accounts.json | 66 ++++ .../test_address_balance-10-get_address.json | 285 ++++++++++++++++++ ...address_balance-20-get_balance-noargs.json | 46 +++ ...st_address_balance-30-get_balance-0-2.json | 35 +++ tests/test_jsonrpcwallet.py | 202 +++++++++++-- 8 files changed, 654 insertions(+), 35 deletions(-) create mode 100644 tests/data/test_jsonrpcwallet/test_address_balance-00-get_accounts.json create mode 100644 tests/data/test_jsonrpcwallet/test_address_balance-10-get_address.json create mode 100644 tests/data/test_jsonrpcwallet/test_address_balance-20-get_balance-noargs.json create mode 100644 tests/data/test_jsonrpcwallet/test_address_balance-30-get_balance-0-2.json diff --git a/monero/account.py b/monero/account.py index 5e7a6ad..a29681a 100644 --- a/monero/account.py +++ b/monero/account.py @@ -70,6 +70,26 @@ class Account(object): """ return self._backend.new_address(account=self.index, label=label) + def address_balance(self, addresses=None): + """ + Returns balances of given addresses, or all addresses if none given. + + :param addresses: a sequence of address as :class:`Address ` + or their indexes within the account as `int`s + :rtype: list of index, subaddress, balance, num_UTXOs: + (`int`, :class:`Address `, `Decimal`, `int`) + """ + indices = None + _addresses = self.addresses() + if addresses is not None: + indices = [] + for addr in addresses: + if isinstance(addr, int): + indices.append(addr) + else: + indices.append(_addresses.index(addr)) + return self._backend.address_balance(account=self.index, indices=indices) + def transfer( self, address, diff --git a/monero/backends/jsonrpc/wallet.py b/monero/backends/jsonrpc/wallet.py index 2c25963..d12f9fc 100644 --- a/monero/backends/jsonrpc/wallet.py +++ b/monero/backends/jsonrpc/wallet.py @@ -122,6 +122,25 @@ class JSONRPCWallet(object): from_atomic(_balance["unlocked_balance"]), ) + def address_balance(self, account=0, indices=None): + indices = [] if indices is None else indices + _balances = self.raw_request( + "getbalance", + { + "account_index": account, + "address_indices": indices, + }, + ) + return [ + ( + bal["address_index"], + address(bal["address"]), + from_atomic(bal["balance"]), + bal["num_unspent_outputs"], + ) + for bal in _balances["per_subaddress"] + ] + def transfers_in(self, account, pmtfilter): params = {"account_index": account, "pending": False} method = "get_transfers" diff --git a/monero/wallet.py b/monero/wallet.py index a996165..8577442 100644 --- a/monero/wallet.py +++ b/monero/wallet.py @@ -211,9 +211,9 @@ class Wallet(object): :rtype: :class:`BaseAddress ` """ # ensure indexes are within uint32 - if major < 0 or major >= 2 ** 32: + if major < 0 or major >= 2**32: raise ValueError("major index {} is outside uint32 range".format(major)) - if minor < 0 or minor >= 2 ** 32: + if minor < 0 or minor >= 2**32: raise ValueError("minor index {} is outside uint32 range".format(minor)) master_address = self.address() if major == minor == 0: @@ -243,6 +243,18 @@ class Wallet(object): checksum = keccak_256(data).digest()[:4] return address.SubAddress(base58.encode(hexlify(data + checksum))) + def address_balance(self, addresses=None): + """ + Returns balances of given addresses, or all addresses if none given. Operates on the + default account. + + :param addresses: a sequence of address as :class:`Address ` + or their indexes within the account as `int`s + :rtype: list of index, subaddress, balance, num_UTXOs: + (`int`, :class:`Address `, `Decimal`, `int`) + """ + return self.accounts[0].address_balance(addresses=addresses) + def transfer( self, address, diff --git a/tests/data/test_jsonrpcwallet/test_address_balance-00-get_accounts.json b/tests/data/test_jsonrpcwallet/test_address_balance-00-get_accounts.json new file mode 100644 index 0000000..2a0b79b --- /dev/null +++ b/tests/data/test_jsonrpcwallet/test_address_balance-00-get_accounts.json @@ -0,0 +1,66 @@ +{ + "id": 0, + "jsonrpc": "2.0", + "result": { + "subaddress_accounts": [ + { + "account_index": 0, + "balance": 12982128625328954, + "base_address": "55LTR8KniP4LQGJSPtbYDacR7dz8RBFnsfAKMaMuwUNYX6aQbBcovzDPyrQF9KXF9tVU6Xk3K8no1BywnJX6GvZX8yJsXvt", + "label": "Primary account", + "tag": "", + "unlocked_balance": 12982128625328954 + }, + { + "account_index": 1, + "balance": 12000000000000, + "base_address": "77Vx9cs1VPicFndSVgYUvTdLCJEZw9h81hXLMYsjBCXSJfUehLa9TDW3Ffh45SQa7xb6dUs18mpNxfUhQGqfwXPSMrvKhVp", + "label": "Untitled account", + "tag": "", + "unlocked_balance": 12000000000000 + }, + { + "account_index": 2, + "balance": 11222000000000, + "base_address": "78P16M3XmFRGcWFCcsgt1WcTntA1jzcq31seQX1Eg92j8VQ99NPivmdKam4J5CKNAD7KuNWcq5xUPgoWczChzdba5WLwQ4j", + "label": "Untitled account", + "tag": "", + "unlocked_balance": 11222000000000 + }, + { + "account_index": 3, + "balance": 2000000000000, + "base_address": "76FWbfaWr3igfJhf2B5zBMjCWKZpaiGHbfE7vqgDGDSGWs2mfTBNHqTTMAqkYsxg6XEojV4Pax8wV9Fqvu1Ghy7nQiSzcXQ", + "label": "Untitled account", + "tag": "", + "unlocked_balance": 2000000000000 + }, + { + "account_index": 4, + "balance": 1000000000000, + "base_address": "77ETXXSc6PkAF7WkJPFoL43ivyoBq9kpC38GbCa7Z6T72VpWXWBKpK6QQgL47VF196h7EFExy43knMYscAyCYz9F44nEDd5", + "label": "Untitled account", + "tag": "", + "unlocked_balance": 1000000000000 + }, + { + "account_index": 5, + "balance": 200000000000000, + "base_address": "73mFYjLVDF9HSaNfAnGpqTBvNaCyBDGqx9NAPaKBhCYWRMxUERWDkk6hgzh4dEuwKTPy3UMdLL91zF5BxrwzBtQNAKfqf5W", + "label": "Untitled account", + "tag": "", + "unlocked_balance": 200000000000000 + }, + { + "account_index": 6, + "balance": 50000000000, + "base_address": "78jehncLRUCKiNHQ1DBqwDBREs32X9Ec1ebU2EFM2cDLah6qDxM4d1RQ9uRymEa71r4qKPxY2KpVv9ueMJEbAHL7RELQqqA", + "label": "Untitled account", + "tag": "", + "unlocked_balance": 50000000000 + } + ], + "total_balance": 13208400625328954, + "total_unlocked_balance": 13208400625328954 + } +} diff --git a/tests/data/test_jsonrpcwallet/test_address_balance-10-get_address.json b/tests/data/test_jsonrpcwallet/test_address_balance-10-get_address.json new file mode 100644 index 0000000..0b05b34 --- /dev/null +++ b/tests/data/test_jsonrpcwallet/test_address_balance-10-get_address.json @@ -0,0 +1,285 @@ +{ + "id": 0, + "jsonrpc": "2.0", + "result": { + "address": "55LTR8KniP4LQGJSPtbYDacR7dz8RBFnsfAKMaMuwUNYX6aQbBcovzDPyrQF9KXF9tVU6Xk3K8no1BywnJX6GvZX8yJsXvt", + "addresses": [ + { + "address": "55LTR8KniP4LQGJSPtbYDacR7dz8RBFnsfAKMaMuwUNYX6aQbBcovzDPyrQF9KXF9tVU6Xk3K8no1BywnJX6GvZX8yJsXvt", + "address_index": 0, + "label": "Primary account", + "used": true + }, + { + "address": "7BnERTpvL5MbCLtj5n9No7J5oE5hHiB3tVCK5cjSvCsYWD2WRJLFuWeKTLiXo5QJqt2ZwUaLy2Vh1Ad51K7FNgqcHgjW85o", + "address_index": 1, + "label": "", + "used": true + }, + { + "address": "75sNpRwUtekcJGejMuLSGA71QFuK1qcCVLZnYRTfQLgFU5nJ7xiAHtR5ihioS53KMe8pBhH61moraZHyLoG4G7fMER8xkNv", + "address_index": 2, + "label": "", + "used": true + }, + { + "address": "74Jsocx8xbpTBEjm3ncKE5LBQbiJouyCDaGhgSiebpvNDXZnTAbW2CmUR5SsBeae2pNk9WMVuz6jegkC4krUyqRjA6VjoLD", + "address_index": 3, + "label": "", + "used": true + }, + { + "address": "77xa6Dha7kzCQuvmd8iB5VYoMkdenwCNRU9khGhExXQ8KLL3z1N1ZATBD1sFPenyHWT9cm4fVFnCAUApY53peuoZFtwZiw5", + "address_index": 4, + "label": "", + "used": true + }, + { + "address": "7BG5jr9QS5sGMdpbBrZEwVLZjSKJGJBsXdZLt8wiXyhhLjy7x2LZxsrAnHTgD8oG46ZtLjUGic2pWc96GFkGNPQQDA3Dt7Q", + "address_index": 5, + "label": "", + "used": true + }, + { + "address": "76d6L8c5TZuPdPFrBtYXGE3uLpUu5LAunZBUQBB9BsoRMAVqkYe2X1NAFxmAnFar9qB37cobaL8fbQEDjGqKzp2DS4aSp16", + "address_index": 6, + "label": "", + "used": true + }, + { + "address": "72Lu6mmyNvqD8gKT5MyAMHgnmya5fjhgFLWyZr4RVRkEF9E6rVoWZt14h1rzBaxLB73JT8N2J92uz778f1pDNe8Z6XFE9dm", + "address_index": 7, + "label": "", + "used": true + }, + { + "address": "77hNE2RbRMJP1SpFnWYAfAVDuBwYY7Yzi3eeTEkvq9PE4K8hAavu9RVWSxx1u34jkMgd1tHPNJYBo96KBitoTAMFSYBeh2u", + "address_index": 8, + "label": "", + "used": true + }, + { + "address": "73UAGqNiN4dUsuY5szeYokA6ENfRA4dt7StnaoBbFAxfYUm7f6gSsZDjJqLdrGAku2G8XoPfDbt9E5DQ2WMiPgxs5ZuqV69", + "address_index": 9, + "label": "", + "used": true + }, + { + "address": "74CMmWRzwRD87FrazYxwd1iuCEahNzXjtHKGW2JsUivH18GjQuEPRPZNiADwNymKUvCibADn9b8Qc5qff7z4QS6NLkHvGyM", + "address_index": 10, + "label": "", + "used": true + }, + { + "address": "72G29XWzmL4DRzR97mafURN3TkYHpVjYuV9wN2YYa5yE8nY3v8MfiCAPVqGEdW4Y3uWFbz8Z3HiX6Nmb4YYNiFsv9zt4mYg", + "address_index": 11, + "label": "", + "used": true + }, + { + "address": "7BADdqPg8tb5Q1k9sPysx7RcjF9nBZZsZBNsHLYiwCXUVFkKN2dHALYLtJX3Q9hCZwFnwEhSyXockGYCGCyMCkZCQtDj8bo", + "address_index": 12, + "label": "", + "used": true + }, + { + "address": "7Bgo2rwc2oCAR3V5CCuoD8fj6VrQ85vMAGz36BDDQDEGYrJiUiQrP4LbynFtqMgFEsAvRSBvTgUYhRuoVdp3QvHVTP6ieZy", + "address_index": 13, + "label": "", + "used": true + }, + { + "address": "787CXWuevtt2SdD9x6rB7hCk73pYVv7HYgAUAPsYQJ9zAmQN7Ksxr5KieQFXuEL6ZSMqMDNbbaUze365iF2DbkjB9bcL82t", + "address_index": 14, + "label": "", + "used": true + }, + { + "address": "77yjHxBeLNq4mf4dhEB7ksD6WDaAEEguqHHvuFYyiLiMWwSrvYHftzT5c1HRS9iWa2UBn4MQLuz8jEiE6sPDfMzB81UMHaK", + "address_index": 15, + "label": "", + "used": true + }, + { + "address": "72quvHYJ8QzivQyV4NMZ9h1gyZXyJZvsWZTwgVFRCw9b1eJ4yibHEnU3CVCCXJ7evqXhSEKJL2rjzCMV3LpXirR5B8EnkaE", + "address_index": 16, + "label": "", + "used": true + }, + { + "address": "78GicYh9qr6TjKhvkDkCwxE84rw6pjLwg433Stwkwdbc8jD9fSBa1Fj6V2TWzYw4j1F3JfymSXftPMb2k72trC6X7DRKyNi", + "address_index": 17, + "label": "", + "used": true + }, + { + "address": "72nfCSqpigFWaMeKyZYjKMQRvYFxWvJaf8Nnb1KxVndeTuL7avqoCF5NME4WGMqwmK58i8BnKxCz543mFoZhuUMpGhN1dcm", + "address_index": 18, + "label": "", + "used": true + }, + { + "address": "76DAGBUvbEGaEHm8HbiFk3R69aQ8qz8WbAuT3MJbs5Eu9Lsiiyk1YB4HxYdimPiLwhMopUibnfzmjQt2uk38GXqh5PbG2zF", + "address_index": 19, + "label": "", + "used": true + }, + { + "address": "79enX1LRA1VKtLVJA9nia7jU1HxD2jQbK72b1UmmfXUWQHRCqWaHoqE27SaP9DgY9PLZJm8g6EQyJfRkV4rrJCjfJfjzR5z", + "address_index": 20, + "label": "", + "used": true + }, + { + "address": "7A4e7DZb1utWQcSEJuKvDeU6SwUmPXgyLDbQHcrD9mSgEVGCwzrothoLEjAipcc1w29uUKctLqFFHeJdB3nrc43tK8ABipr", + "address_index": 21, + "label": "", + "used": true + }, + { + "address": "741XkfSab833hJs8no7JwYEoFwA9rwgQYRtS8L8c8oPo87P6By2QW8GjEfqZXFbrtL2mxH11TC5gXjewW6kNcdzPFXAWhQR", + "address_index": 22, + "label": "", + "used": true + }, + { + "address": "79Vz3pwqLG2c34cNTfReDQJpER1sG6d4G5GAvkx1Zo8k7K2fe4RKykoJqbXpY4BuYXReEBby1GxsMBEQUwi2YQL85vK3yrx", + "address_index": 23, + "label": "", + "used": true + }, + { + "address": "74yvu7FfnBuLd4RP8rng6hQX3DhGsfR8S8DHZbkU7Nc72oSbrs4QZzedQ3r4e9u4Cs4GrREJazTwARsrM7QZmS26CSvpF2o", + "address_index": 24, + "label": "", + "used": true + }, + { + "address": "78ii4zuc2hf5yxbCRB83C1PYphnLEziyoNaU42zbyW97i9kBkJvUKQPPQxRQMbCfwpDvdRBDhsDz6SuU3phB2YfqDMrJnpN", + "address_index": 25, + "label": "", + "used": true + }, + { + "address": "79KjVTgMA9Meykhet9bc3e7eouVmbjSW94dHm8GR8Z7aXWKFUw2SfqTLDuVZLeQ67a1U7auXRLTZC2bVWYjsEBdQBUGVRT6", + "address_index": 26, + "label": "", + "used": true + }, + { + "address": "7BBLN3nNNk2hgCFvRFpsHZAPyXXiwFt8B638oL2Pkt3TFnbDcgr5WGM7vpPPPFdKa1gJC7K4a17LTCd6n9psJFfKE7qL8Mg", + "address_index": 27, + "label": "", + "used": true + }, + { + "address": "789JQ5k47TNEExem6Gia8a1XpRHKzqdCmNMJyCPQYwfFDzimHuYAszSVPV8MeG2hg5J3SkpyW4sP1Mogi7pFH3rL59fPJ6N", + "address_index": 28, + "label": "", + "used": true + }, + { + "address": "76Gn6Qa5JWMZLLiE52nogbB4PU3bpfJQSg14WDh3BYkFFG73xHwjemN6265FWxS5awg4gsRPEFqLXCNw1R9ebbPQRSxnEjX", + "address_index": 29, + "label": "", + "used": true + }, + { + "address": "76jM8BCrf5qTVKWYmsbC3mjegAm5Qdt7EPVamNaihH5D3dwCqwDTY6MRhuW2XkhrggH2HsCtiUvQMPpwVxTHj7roVhjyhw3", + "address_index": 30, + "label": "", + "used": true + }, + { + "address": "77fvk3jcLL1E9LtMKg3wHfG5RYgBTXTa5YFG6fS7VpbtYHshUjTbZQFJcmnp4Q6KyhbTFeMEaUCXkPUvxqSEjKXB1yobK34", + "address_index": 31, + "label": "", + "used": true + }, + { + "address": "7AaMjWhnqHAXW6APWbBsNTiqWwRmQdsrsbNVjPHmURASHvYGRksd8YW2Hcw5G9Cy7pVbmJAFGo6n51KmBoANX3rnQ9Ls1AY", + "address_index": 32, + "label": "", + "used": true + }, + { + "address": "75AxHhjuJw5aRAnTaduuxU3oCt5o2M1sTMjQXEbubX3CJ5V2PvW5XbxRgzPh4BZsDsCFeHeScZCqVYcyhcF16S5xV7duLGS", + "address_index": 33, + "label": "", + "used": true + }, + { + "address": "77rtREYCDyDQFd6RfrY36S4cXbnb3s9WB8j1ttYEJNPE1B9b84kcGaH26bXwetxt5T87irvhJKqYXRbvVAAf8rpcMZEaVCw", + "address_index": 34, + "label": "", + "used": true + }, + { + "address": "7BgdbHix1zZKmWZtDDdKFU8Cc2m2i9vR1PWMTjaUdS43ZmuQ2MbKwMjJ1cXKSdQdC4i8AE14RikQZ4gqx6DjkfB2EvnPpYi", + "address_index": 35, + "label": "", + "used": true + }, + { + "address": "74jYdMUHpUPbK3rooD4ktnHSMwgBxdoWH9nkK5NCnpQSKRuiDadq4MmZTLqKWqKJfYDrR3qhV8SWUPn8s4bLBtLfL4W9etH", + "address_index": 36, + "label": "", + "used": true + }, + { + "address": "72qGoKbwNESTwsbwoRiGHW7d3txxmyfEVAzdB1ARTUT6gc6JgZb7B8XBMmyYX1nL1GebBp1V2Aea9Ji3NXG9pbtdUvkxQNC", + "address_index": 37, + "label": "", + "used": true + }, + { + "address": "7AWXV26SHCZB3eaGjXm8qcPmHbWgqnXFnP15AKpyu2tPFPSuV9XX6UAaAoA8PARmr74CaxAwUs1QThaZu5CjQbabK8k4uen", + "address_index": 38, + "label": "", + "used": true + }, + { + "address": "7AvrWUSu8xx1hn6QxmqX1EAr6Vh3uqw6Q3ZxFritkTJ8EXTdsCHkp3BAL4CBVnahz8B7h9CmNR8Z96YV72B9JjsLTYVTF5H", + "address_index": 39, + "label": "", + "used": true + }, + { + "address": "74JrAfcBuPGK5Kdj1vwjDZBX35iWMYMRffPT2JimDuSpgGr4ZDHtUqcA1fr19SD7bL925b7VURRYFbcfCKejJgS4FJidJFZ", + "address_index": 40, + "label": "", + "used": true + }, + { + "address": "7BJNqyrMig975E6GpMcD9UNnWGipeWe6RDcgmV5xguC1FpE7f4bS4bQMSJ4Py9q7am4rBG6VCyQ74e5iVpXyQf3cSTKN6Tu", + "address_index": 41, + "label": "", + "used": true + }, + { + "address": "79sRbDppUyW7Fvbh7mDNPuS3u5eJy7ppt6uNyhE7E5JxNJhMRAwyNNHfbuYZjh1Z1V8sPikPfxj4CNHqH4wEo5vfU4QuPxZ", + "address_index": 42, + "label": "", + "used": true + }, + { + "address": "7AhixSjBWUWTgRhTSEYBd3CxVraX6gsKddUoTUk7M2CG6H44jsuyaWggi3fZNSTq9tf4oecahM7ksa2mCLhuHL5rDpkX13S", + "address_index": 43, + "label": "", + "used": true + }, + { + "address": "79noNe548PAHExvLDXmXRiNRCkcBaY4UMZGW4dZ6nYKgAYGhTrTkGgzQER8cDkFScC312ttLnrmeG7fkskYQvu5159aPhCC", + "address_index": 44, + "label": "", + "used": true + }, + { + "address": "77rnp6jb3bh56UvJ2xfYeiavRc3SusVckhAgfA9etsABDGJPsKcrWxWMVqRwakFxKqS2GpHttcLbDbhefxaXqVQ7HP5wUt6", + "address_index": 45, + "label": "", + "used": true + } + ] + } +} diff --git a/tests/data/test_jsonrpcwallet/test_address_balance-20-get_balance-noargs.json b/tests/data/test_jsonrpcwallet/test_address_balance-20-get_balance-noargs.json new file mode 100644 index 0000000..f3a4fbb --- /dev/null +++ b/tests/data/test_jsonrpcwallet/test_address_balance-20-get_balance-noargs.json @@ -0,0 +1,46 @@ +{ + "id": 0, + "jsonrpc": "2.0", + "result": { + "balance": 12982128625328954, + "blocks_to_unlock": 0, + "multisig_import_needed": false, + "per_subaddress": [ + { + "account_index": 0, + "address": "55LTR8KniP4LQGJSPtbYDacR7dz8RBFnsfAKMaMuwUNYX6aQbBcovzDPyrQF9KXF9tVU6Xk3K8no1BywnJX6GvZX8yJsXvt", + "address_index": 0, + "balance": 12943277373064573, + "blocks_to_unlock": 0, + "label": "Primary account", + "num_unspent_outputs": 1291, + "time_to_unlock": 0, + "unlocked_balance": 12943277373064573 + }, + { + "account_index": 0, + "address": "7BnERTpvL5MbCLtj5n9No7J5oE5hHiB3tVCK5cjSvCsYWD2WRJLFuWeKTLiXo5QJqt2ZwUaLy2Vh1Ad51K7FNgqcHgjW85o", + "address_index": 1, + "balance": 38051052264381, + "blocks_to_unlock": 0, + "label": "", + "num_unspent_outputs": 75, + "time_to_unlock": 0, + "unlocked_balance": 38051052264381 + }, + { + "account_index": 0, + "address": "75sNpRwUtekcJGejMuLSGA71QFuK1qcCVLZnYRTfQLgFU5nJ7xiAHtR5ihioS53KMe8pBhH61moraZHyLoG4G7fMER8xkNv", + "address_index": 2, + "balance": 800200000000, + "blocks_to_unlock": 0, + "label": "", + "num_unspent_outputs": 5, + "time_to_unlock": 0, + "unlocked_balance": 800200000000 + } + ], + "time_to_unlock": 0, + "unlocked_balance": 12982128625328954 + } +} diff --git a/tests/data/test_jsonrpcwallet/test_address_balance-30-get_balance-0-2.json b/tests/data/test_jsonrpcwallet/test_address_balance-30-get_balance-0-2.json new file mode 100644 index 0000000..bcdf177 --- /dev/null +++ b/tests/data/test_jsonrpcwallet/test_address_balance-30-get_balance-0-2.json @@ -0,0 +1,35 @@ +{ + "id": 0, + "jsonrpc": "2.0", + "result": { + "balance": 12982128625328954, + "blocks_to_unlock": 0, + "multisig_import_needed": false, + "per_subaddress": [ + { + "account_index": 0, + "address": "55LTR8KniP4LQGJSPtbYDacR7dz8RBFnsfAKMaMuwUNYX6aQbBcovzDPyrQF9KXF9tVU6Xk3K8no1BywnJX6GvZX8yJsXvt", + "address_index": 0, + "balance": 12943277373064573, + "blocks_to_unlock": 0, + "label": "Primary account", + "num_unspent_outputs": 1291, + "time_to_unlock": 0, + "unlocked_balance": 12943277373064573 + }, + { + "account_index": 0, + "address": "75sNpRwUtekcJGejMuLSGA71QFuK1qcCVLZnYRTfQLgFU5nJ7xiAHtR5ihioS53KMe8pBhH61moraZHyLoG4G7fMER8xkNv", + "address_index": 2, + "balance": 800200000000, + "blocks_to_unlock": 0, + "label": "", + "num_unspent_outputs": 5, + "time_to_unlock": 0, + "unlocked_balance": 800200000000 + } + ], + "time_to_unlock": 0, + "unlocked_balance": 12982128625328954 + } +} diff --git a/tests/test_jsonrpcwallet.py b/tests/test_jsonrpcwallet.py index cf9781e..8f55171 100644 --- a/tests/test_jsonrpcwallet.py +++ b/tests/test_jsonrpcwallet.py @@ -2,11 +2,7 @@ from datetime import datetime from decimal import Decimal import responses import requests - -try: - from unittest.mock import patch, Mock -except ImportError: - from mock import patch, Mock +from unittest.mock import patch from monero.wallet import Wallet from monero.address import BaseAddress, Address, SubAddress @@ -220,6 +216,146 @@ class JSONRPCWalletTestCase(JSONTestCase): self.assertIsInstance(subaddr, SubAddress) self.assertIsInstance(index, int) + @responses.activate + def test_address_balance(self): + responses.add( + responses.POST, + self.jsonrpc_url, + json=self._read("test_address_balance-00-get_accounts.json"), + status=200, + ) + responses.add( + responses.POST, + self.jsonrpc_url, + json=self._read("test_address_balance-10-get_address.json"), + status=200, + ) + responses.add( + responses.POST, + self.jsonrpc_url, + json=self._read("test_address_balance-20-get_balance-noargs.json"), + status=200, + ) + responses.add( + responses.POST, + self.jsonrpc_url, + json=self._read("test_address_balance-10-get_address.json"), + status=200, + ) + responses.add( + responses.POST, + self.jsonrpc_url, + json=self._read("test_address_balance-30-get_balance-0-2.json"), + status=200, + ) + responses.add( + responses.POST, + self.jsonrpc_url, + json=self._read("test_address_balance-10-get_address.json"), + status=200, + ) + responses.add( + responses.POST, + self.jsonrpc_url, + json=self._read("test_address_balance-30-get_balance-0-2.json"), + status=200, + ) + responses.add( + responses.POST, + self.jsonrpc_url, + json=self._read("test_address_balance-10-get_address.json"), + status=200, + ) + responses.add( + responses.POST, + self.jsonrpc_url, + json=self._read("test_address_balance-30-get_balance-0-2.json"), + status=200, + ) + responses.add( + responses.POST, + self.jsonrpc_url, + json=self._read("test_address_balance-10-get_address.json"), + status=200, + ) + responses.add( + responses.POST, + self.jsonrpc_url, + json=self._read("test_address_balance-30-get_balance-0-2.json"), + status=200, + ) + w = Wallet(JSONRPCWallet()) + addrbal_noparams = w.address_balance() + addrbal_a0_a2 = w.address_balance( + addresses=( + "55LTR8KniP4LQGJSPtbYDacR7dz8RBFnsfAKMaMuwUNYX6aQbBcovzDPyrQF9KXF9tVU6Xk3K8no1BywnJX6GvZX8yJsXvt", + "75sNpRwUtekcJGejMuLSGA71QFuK1qcCVLZnYRTfQLgFU5nJ7xiAHtR5ihioS53KMe8pBhH61moraZHyLoG4G7fMER8xkNv", + ) + ) + addrbal_i0_a2 = w.address_balance( + addresses=[ + 0, + "75sNpRwUtekcJGejMuLSGA71QFuK1qcCVLZnYRTfQLgFU5nJ7xiAHtR5ihioS53KMe8pBhH61moraZHyLoG4G7fMER8xkNv", + ] + ) + addrbal_a0_i2 = w.address_balance( + addresses={ + "55LTR8KniP4LQGJSPtbYDacR7dz8RBFnsfAKMaMuwUNYX6aQbBcovzDPyrQF9KXF9tVU6Xk3K8no1BywnJX6GvZX8yJsXvt", + 2, + } + ) + addrbal_i0_i2 = w.address_balance( + addresses=( + 0, + 2, + ) + ) + # make sure all parametrized sequences are equal + self.assertSequenceEqual(addrbal_a0_a2, addrbal_i0_i2) + self.assertSequenceEqual(addrbal_i0_a2, addrbal_a0_i2) + self.assertSequenceEqual(addrbal_i0_a2, addrbal_i0_i2) + # check the final results + self.assertSequenceEqual( + addrbal_noparams, + [ + ( + 0, + "55LTR8KniP4LQGJSPtbYDacR7dz8RBFnsfAKMaMuwUNYX6aQbBcovzDPyrQF9KXF9tVU6Xk3K8no1BywnJX6GvZX8yJsXvt", + Decimal("12943.277373064573"), + 1291, + ), + ( + 1, + "7BnERTpvL5MbCLtj5n9No7J5oE5hHiB3tVCK5cjSvCsYWD2WRJLFuWeKTLiXo5QJqt2ZwUaLy2Vh1Ad51K7FNgqcHgjW85o", + Decimal("38.051052264381"), + 75, + ), + ( + 2, + "75sNpRwUtekcJGejMuLSGA71QFuK1qcCVLZnYRTfQLgFU5nJ7xiAHtR5ihioS53KMe8pBhH61moraZHyLoG4G7fMER8xkNv", + Decimal("0.800200000000"), + 5, + ), + ], + ) + self.assertSequenceEqual( + addrbal_a0_a2, + [ + ( + 0, + "55LTR8KniP4LQGJSPtbYDacR7dz8RBFnsfAKMaMuwUNYX6aQbBcovzDPyrQF9KXF9tVU6Xk3K8no1BywnJX6GvZX8yJsXvt", + Decimal("12943.277373064573"), + 1291, + ), + ( + 2, + "75sNpRwUtekcJGejMuLSGA71QFuK1qcCVLZnYRTfQLgFU5nJ7xiAHtR5ihioS53KMe8pBhH61moraZHyLoG4G7fMER8xkNv", + Decimal("0.800200000000"), + 5, + ), + ], + ) + @patch.object(requests.Session, "post") def test_incoming_confirmed(self, mock_post): mock_post.return_value.status_code = 200 @@ -1603,9 +1739,9 @@ class JSONRPCWalletTestCase(JSONTestCase): } outs_hex = self.wallet.export_outputs() mock_post.return_value.json.return_value = { - u"id": 0, - u"jsonrpc": u"2.0", - u"result": {u"num_imported": 9}, + "id": 0, + "jsonrpc": "2.0", + "result": {"num_imported": 9}, } self.assertEqual(self.wallet.import_outputs(outs_hex), 9) @@ -1616,54 +1752,54 @@ class JSONRPCWalletTestCase(JSONTestCase): self.wallet = Wallet(JSONRPCWallet()) mock_post.return_value.status_code = 200 mock_post.return_value.json.return_value = { - u"id": 0, - u"jsonrpc": u"2.0", - u"result": { - u"signed_key_images": [ + "id": 0, + "jsonrpc": "2.0", + "result": { + "signed_key_images": [ { - u"key_image": u"0100000000000000000000000000000000000000000000000000000000000000", - u"signature": u"ffe0d3216dc7a9f44dd997e7412ecb4a5e03641bba27119bbc0d5b6a145955048f4a8f301826c0d5999264cbc67817a6643143c49195a56fd135936667db0e08", + "key_image": "0100000000000000000000000000000000000000000000000000000000000000", + "signature": "ffe0d3216dc7a9f44dd997e7412ecb4a5e03641bba27119bbc0d5b6a145955048f4a8f301826c0d5999264cbc67817a6643143c49195a56fd135936667db0e08", }, { - u"key_image": u"0100000000000000000000000000000000000000000000000000000000000000", - u"signature": u"0ed0b9752eb5d2466985174c50453f3fc9bd271b1f95bfd50d484b958976c40e8e1a7584cde52a85d40edc4a1bf9684003436492364af0ad9e1d4add1e158108", + "key_image": "0100000000000000000000000000000000000000000000000000000000000000", + "signature": "0ed0b9752eb5d2466985174c50453f3fc9bd271b1f95bfd50d484b958976c40e8e1a7584cde52a85d40edc4a1bf9684003436492364af0ad9e1d4add1e158108", }, { - u"key_image": u"0100000000000000000000000000000000000000000000000000000000000000", - u"signature": u"b54632f4e95f70eb1af6459c94694c65ff1b8c822b40a62e6ef7cc1c6a055b0bb4b3832d48330c863993bf46bf87e1ed2971bf6a5d94a9a333a59017fb83630e", + "key_image": "0100000000000000000000000000000000000000000000000000000000000000", + "signature": "b54632f4e95f70eb1af6459c94694c65ff1b8c822b40a62e6ef7cc1c6a055b0bb4b3832d48330c863993bf46bf87e1ed2971bf6a5d94a9a333a59017fb83630e", }, { - u"key_image": u"0100000000000000000000000000000000000000000000000000000000000000", - u"signature": u"57f85fd761ecb780a877034cef57449df7c3ad492d803711d1b2a47bf192d00af2f2341388120364dba0d7496c0a5d041032602812995c11268253618713040a", + "key_image": "0100000000000000000000000000000000000000000000000000000000000000", + "signature": "57f85fd761ecb780a877034cef57449df7c3ad492d803711d1b2a47bf192d00af2f2341388120364dba0d7496c0a5d041032602812995c11268253618713040a", }, { - u"key_image": u"0100000000000000000000000000000000000000000000000000000000000000", - u"signature": u"9d22b52da3b835afbf29de7ba2dd86fb805435492691799debd7d37dd932dc0e4b07e9b4744da38e2b38fac63475522112804627227756bc37dbc57ea7e59701", + "key_image": "0100000000000000000000000000000000000000000000000000000000000000", + "signature": "9d22b52da3b835afbf29de7ba2dd86fb805435492691799debd7d37dd932dc0e4b07e9b4744da38e2b38fac63475522112804627227756bc37dbc57ea7e59701", }, { - u"key_image": u"0100000000000000000000000000000000000000000000000000000000000000", - u"signature": u"664c7ac1c1f4c86e56ebc5298ef4acf46c2c154263c5dbc69b5d4d08b9f31a001db8845dbe37a81e7289e33f24ab5b0f17bbfe00612e4624c7b27ca0c27e5c0c", + "key_image": "0100000000000000000000000000000000000000000000000000000000000000", + "signature": "664c7ac1c1f4c86e56ebc5298ef4acf46c2c154263c5dbc69b5d4d08b9f31a001db8845dbe37a81e7289e33f24ab5b0f17bbfe00612e4624c7b27ca0c27e5c0c", }, { - u"key_image": u"0100000000000000000000000000000000000000000000000000000000000000", - u"signature": u"a6bf6c5248b00f946ced5d21d03311fa6335b0ddf37f8e46d89d4b0a73de7b040d7ceee31da144693a8f86b1e61908014783e139061c0a4015b0ef13a967060c", + "key_image": "0100000000000000000000000000000000000000000000000000000000000000", + "signature": "a6bf6c5248b00f946ced5d21d03311fa6335b0ddf37f8e46d89d4b0a73de7b040d7ceee31da144693a8f86b1e61908014783e139061c0a4015b0ef13a967060c", }, { - u"key_image": u"0100000000000000000000000000000000000000000000000000000000000000", - u"signature": u"2d6792c9c438657a5a2d7068f16fe80ca7995144ec1f12f1a37c091690cf260323bbe866e88d725dc791344e6af29b0f22d0792b9f60a5020c6e54bad7fe1404", + "key_image": "0100000000000000000000000000000000000000000000000000000000000000", + "signature": "2d6792c9c438657a5a2d7068f16fe80ca7995144ec1f12f1a37c091690cf260323bbe866e88d725dc791344e6af29b0f22d0792b9f60a5020c6e54bad7fe1404", }, { - u"key_image": u"0100000000000000000000000000000000000000000000000000000000000000", - u"signature": u"a5fe1c57e83442856b1e3cefc67814c908f2485269adbe808c013c7ddb489c0592278fec3c7cc32b2d16135e627fe7bf42ab896e0c7a17333f176ff8bf267f04", + "key_image": "0100000000000000000000000000000000000000000000000000000000000000", + "signature": "a5fe1c57e83442856b1e3cefc67814c908f2485269adbe808c013c7ddb489c0592278fec3c7cc32b2d16135e627fe7bf42ab896e0c7a17333f176ff8bf267f04", }, ] }, } kimgs = self.wallet.export_key_images() mock_post.return_value.json.return_value = { - u"id": 0, - u"jsonrpc": u"2.0", - u"result": {u"height": 125578, u"spent": 322437994530000, u"unspent": 0}, + "id": 0, + "jsonrpc": "2.0", + "result": {"height": 125578, "spent": 322437994530000, "unspent": 0}, } self.assertEqual( self.wallet.import_key_images(kimgs),