diff --git a/client/api/api_nodes.py b/client/api/api_nodes.py index f4fca6a..d2295e0 100644 --- a/client/api/api_nodes.py +++ b/client/api/api_nodes.py @@ -1,7 +1,11 @@ +from typing import Optional + from client.resource import Resource +from client.types import PaginatedResponse +from client.types.api_nodes import ApiNodeResponse, ApiNodesQuery class ApiNodes(Resource): - def all(self, query={}): + def all(self, query: Optional[ApiNodesQuery] = None) -> PaginatedResponse[ApiNodeResponse]: return self.with_endpoint('api').request_get('api-nodes', query) diff --git a/client/api/blockchain.py b/client/api/blockchain.py index ee5797e..fa3f5a0 100644 --- a/client/api/blockchain.py +++ b/client/api/blockchain.py @@ -1,7 +1,9 @@ from client.resource import Resource +from client.types import Response +from client.types.blockchain import BlockchainResponse class Blockchain(Resource): - def blockchain(self): + def blockchain(self) -> Response[BlockchainResponse]: return self.with_endpoint('api').request_get('blockchain') diff --git a/client/api/blocks.py b/client/api/blocks.py index 2203f5b..a4cf23b 100644 --- a/client/api/blocks.py +++ b/client/api/blocks.py @@ -1,21 +1,30 @@ +from typing import Optional + from client.resource import Resource +from client.types import PaginatedResponse, Response +from client.types.blocks import BlockResponse, BlockTransactionsQuery, BlocksQuery +from client.types.transactions import TransactionResponse class Blocks(Resource): - def all(self, query={}): + def all(self, query: Optional[BlocksQuery] = None) -> PaginatedResponse[BlockResponse]: return self.with_endpoint('api').request_get('blocks', query) - def get(self, block_id): - return self.with_endpoint('api').request_get(f'blocks/{block_id}') + def get(self, block_hash: str) -> Response[BlockResponse]: + return self.with_endpoint('api').request_get(f'blocks/{block_hash}') - def first(self): + def first(self) -> Response[BlockResponse]: return self.with_endpoint('api').request_get('blocks/first') - def last(self): + def last(self) -> Response[BlockResponse]: return self.with_endpoint('api').request_get('blocks/last') - def transactions(self, block_id, query={}): + def transactions( + self, + block_hash: str, + query: Optional[BlockTransactionsQuery] = None, + ) -> PaginatedResponse[TransactionResponse]: return self.with_endpoint('api').request_get( - f'blocks/{block_id}/transactions', query + f'blocks/{block_hash}/transactions', query ) diff --git a/client/api/commits.py b/client/api/commits.py index b94206c..3430c6b 100644 --- a/client/api/commits.py +++ b/client/api/commits.py @@ -1,7 +1,9 @@ from client.resource import Resource +from client.types import Response +from client.types.commits import CommitResponse class Commits(Resource): - def show(self, block_number): - return self.with_endpoint('api').request_get(f'commits/{block_number}') + def get(self, height: int) -> Response[CommitResponse]: + return self.with_endpoint('api').request_get(f'commits/{height}') diff --git a/client/api/contracts.py b/client/api/contracts.py index 1148236..eedd4b5 100644 --- a/client/api/contracts.py +++ b/client/api/contracts.py @@ -1,10 +1,12 @@ from client.resource import Resource +from client.types import Response +from client.types.contracts import ContractAbiResponse, ContractResponse class Contracts(Resource): - def all(self): + def all(self) -> Response[ContractResponse]: return self.with_endpoint('api').request_get('contracts') - def abi(self, name: str, implementation: str): + def abi(self, name: str, implementation: str) -> Response[ContractAbiResponse]: return self.with_endpoint('api').request_get(f'contracts/{name}/{implementation}/abi') diff --git a/client/api/evm.py b/client/api/evm.py index 9386134..c8189c3 100644 --- a/client/api/evm.py +++ b/client/api/evm.py @@ -1,10 +1,10 @@ -from typing import Any from client.resource import Resource +from client.types.evm import EvmBodyPartialParams class EVM(Resource): - def call(self, params: dict[str, Any]): + def call(self, payload: EvmBodyPartialParams): return self.with_endpoint('evm').request_post('', { 'jsonrpc': "2.0", - **params, + **payload, }) diff --git a/client/api/node.py b/client/api/node.py index 9bb0304..7bc17a2 100644 --- a/client/api/node.py +++ b/client/api/node.py @@ -1,23 +1,30 @@ +from typing import Optional + from client.resource import Resource +from client.types import Response +from client.types.node import ( + NodeConfigurationResponse, + NodeCryptoResponse, + NodeFeesQuery, + NodeFeesResponse, + NodeStatusResponse, + NodeSyncingResponse, +) class Node(Resource): - def status(self): + def status(self) -> Response[NodeStatusResponse]: return self.with_endpoint('api').request_get('node/status') - def syncing(self): + def syncing(self) -> Response[NodeSyncingResponse]: return self.with_endpoint('api').request_get('node/syncing') - def configuration(self): - return self.with_endpoint('api').request_get( - 'node/configuration' - ) + def configuration(self) -> Response[NodeConfigurationResponse]: + return self.with_endpoint('api').request_get('node/configuration') - def crypto(self): - return self.with_endpoint('api').request_get( - 'node/configuration/crypto' - ) + def crypto(self) -> Response[NodeCryptoResponse]: + return self.with_endpoint('api').request_get('node/configuration/crypto') - def fees(self, query={}): + def fees(self, query: Optional[NodeFeesQuery] = None) -> Response[NodeFeesResponse]: return self.with_endpoint('api').request_get('node/fees', query) diff --git a/client/api/peers.py b/client/api/peers.py index 17c9389..ffab350 100644 --- a/client/api/peers.py +++ b/client/api/peers.py @@ -1,10 +1,14 @@ +from typing import Optional + from client.resource import Resource +from client.types import PaginatedResponse, Response +from client.types.peers import PeerResponse, PeersQuery class Peers(Resource): - def all(self, query={}): + def all(self, query: Optional[PeersQuery] = None) -> PaginatedResponse[PeerResponse]: return self.with_endpoint('api').request_get('peers', query) - def get(self, ip): + def get(self, ip: str) -> Response[PeerResponse]: return self.with_endpoint('api').request_get(f'peers/{ip}') diff --git a/client/api/receipts.py b/client/api/receipts.py index 903585a..765e39d 100644 --- a/client/api/receipts.py +++ b/client/api/receipts.py @@ -1,11 +1,25 @@ +from typing import Optional + from client.resource import Resource +from client.types import PaginatedResponse, Response +from client.types.receipts import ReceiptContractsQuery, ReceiptQuery, ReceiptResponse, ReceiptsQuery class Receipts(Resource): - def all(self, query={}): + + def all(self, query: Optional[ReceiptsQuery] = None) -> PaginatedResponse[ReceiptResponse]: return self.with_endpoint('api').request_get('receipts', query) - def get(self, transaction_hash: str): + def get( + self, + transaction_hash: str, + query: Optional[ReceiptQuery] = None, + ) -> Response[ReceiptResponse]: + return self.with_endpoint('api').request_get( + f'receipts/{transaction_hash}', query + ) + + def contracts(self, query: Optional[ReceiptContractsQuery] = None) -> PaginatedResponse[ReceiptResponse]: return self.with_endpoint('api').request_get( - f'receipts/{transaction_hash}' + 'receipts/contracts', query ) diff --git a/client/api/rounds.py b/client/api/rounds.py index 53ba93f..82ab693 100644 --- a/client/api/rounds.py +++ b/client/api/rounds.py @@ -1,15 +1,19 @@ +from typing import Optional + from client.resource import Resource +from client.types import PaginatedQuery, PaginatedResponse, Response +from client.types.rounds import RoundResponse class Rounds(Resource): - def all(self, query={}): + def all(self, query: Optional[PaginatedQuery] = None) -> PaginatedResponse[RoundResponse]: return self.with_endpoint('api').request_get('rounds', query) - def show(self, round_id): + def show(self, round_id: str) -> Response[RoundResponse]: return self.with_endpoint('api').request_get(f'rounds/{round_id}') - def validators(self, round_id): + def validators(self, round_id: str) -> Response[RoundResponse]: return self.with_endpoint('api').request_get( f'rounds/{round_id}/validators' ) diff --git a/client/api/tokens.py b/client/api/tokens.py index 6ee33ad..93f5285 100644 --- a/client/api/tokens.py +++ b/client/api/tokens.py @@ -1,27 +1,65 @@ +from typing import Optional + from client.resource import Resource +from client.types import PaginatedQuery, PaginatedResponse, Response +from client.types.tokens import ( + TokenActionsResponse, + TokenAddressHoldersResponse, + TokenAddressesResponse, + TokenApprovalsQuery, + TokenLookupQuery, + TokenPaginatedResponseResults, + TokenResponse, + TokenTransfersQuery, + TokenWhitelistResponse, + TokensQuery, +) class Tokens(Resource): - def all(self, query={}): + def all(self, query: Optional[TokensQuery] = None) -> PaginatedResponse[TokenResponse]: return self.with_endpoint('api').request_get('tokens', query) - def get(self, address): + def transfers(self, query: Optional[TokenTransfersQuery] = None) -> TokenPaginatedResponseResults[TokenActionsResponse]: return self.with_endpoint('api').request_get( - f'tokens/{address}' + 'tokens/transfers', query + ) + + def approvals(self, query: Optional[TokenApprovalsQuery] = None) -> TokenPaginatedResponseResults[TokenActionsResponse]: + return self.with_endpoint('api').request_get( + 'tokens/approvals', query + ) + + def whitelist(self, query: Optional[PaginatedQuery] = None) -> PaginatedResponse[TokenWhitelistResponse]: + return self.with_endpoint('api').request_get( + 'tokens/whitelist', query ) - def holders(self, address, query={}): + def get(self, address: str) -> Response[TokenAddressesResponse]: return self.with_endpoint('api').request_get( - f'tokens/{address}/holders', query + f'tokens/{address}' ) - def transfers_by_token(self, address, query={}): + def transfers_for( + self, + address: str, + query: Optional[TokenLookupQuery] = None, + ) -> TokenPaginatedResponseResults[TokenActionsResponse]: return self.with_endpoint('api').request_get( f'tokens/{address}/transfers', query ) - def transfers(self, query={}): + def approvals_for( + self, + address: str, + query: Optional[TokenLookupQuery] = None, + ) -> TokenPaginatedResponseResults[TokenActionsResponse]: return self.with_endpoint('api').request_get( - 'tokens/transfers', query + f'tokens/{address}/approvals', query + ) + + def holders_for(self, address: str) -> PaginatedResponse[TokenAddressHoldersResponse]: + return self.with_endpoint('api').request_get( + f'tokens/{address}/holders' ) diff --git a/client/api/transactions.py b/client/api/transactions.py index 7587a19..ab6d8d3 100644 --- a/client/api/transactions.py +++ b/client/api/transactions.py @@ -1,34 +1,52 @@ +from typing import Optional, Sequence + from client.resource import Resource +from client.types import PaginatedResponse, Response +from client.types.transactions import ( + TransactionConfigurationResponse, + TransactionCreateResponse, + TransactionGetQuery, + TransactionResponse, + TransactionsQuery, + UnconfirmedTransactionsQuery, +) class Transactions(Resource): - def all(self, query={}): + def all(self, query: Optional[TransactionsQuery] = None) -> PaginatedResponse[TransactionResponse]: return self.with_endpoint('api').request_get( 'transactions', query ) - def create(self, transactions): + def create(self, transactions: Sequence[str]) -> Response[TransactionCreateResponse]: return self.with_endpoint('transactions').request_post( 'transactions', data={'transactions': transactions} ) - def get(self, transaction_id): + def get( + self, + transaction_id: str, + query: Optional[TransactionGetQuery] = None, + ) -> Response[TransactionResponse]: return self.with_endpoint('api').request_get( - f'transactions/{transaction_id}' + f'transactions/{transaction_id}', query ) - def all_unconfirmed(self, query={}): - return self.with_endpoint('api').request_get( + def all_unconfirmed( + self, + query: Optional[UnconfirmedTransactionsQuery] = None, + ) -> PaginatedResponse[TransactionResponse]: + return self.with_endpoint('transactions').request_get( 'transactions/unconfirmed', query ) - def get_unconfirmed(self, transaction_id): - return self.with_endpoint('api').request_get( + def get_unconfirmed(self, transaction_id: str) -> Response[TransactionResponse]: + return self.with_endpoint('transactions').request_get( f'transactions/unconfirmed/{transaction_id}' ) - def configuration(self): + def configuration(self) -> Response[TransactionConfigurationResponse]: return self.with_endpoint('transactions').request_get( 'configuration' ) diff --git a/client/api/validators.py b/client/api/validators.py index eed26ab..54bda0e 100644 --- a/client/api/validators.py +++ b/client/api/validators.py @@ -1,22 +1,37 @@ +from typing import Optional + from client.resource import Resource +from client.types import PaginatedResponse, Response +from client.types.blocks import BlocksQuery +from client.types.transactions import TransactionResponse +from client.types.validators import ValidatorsQuery +from client.types.wallets import WalletResponse, WalletsQuery class Validators(Resource): - def all(self, query={}): + def all(self, query: Optional[ValidatorsQuery] = None) -> PaginatedResponse[WalletResponse]: return self.with_endpoint('api').request_get('validators', query) - def get(self, validator_id): + def get(self, validator_id: str) -> Response[WalletResponse]: return self.with_endpoint('api').request_get( f'validators/{validator_id}' ) - def blocks(self, validator_id, query={}): + def blocks( + self, + validator_id: str, + query: Optional[BlocksQuery] = None, + ) -> PaginatedResponse[TransactionResponse]: return self.with_endpoint('api').request_get( f'validators/{validator_id}/blocks', query ) - def voters(self, validator_id, query={}): + def voters( + self, + validator_id: str, + query: Optional[WalletsQuery] = None, + ) -> PaginatedResponse[WalletResponse]: return self.with_endpoint('api').request_get( f'validators/{validator_id}/voters', query ) diff --git a/client/api/votes.py b/client/api/votes.py index 4bc7632..5e22e3b 100644 --- a/client/api/votes.py +++ b/client/api/votes.py @@ -1,10 +1,15 @@ +from typing import Optional + from client.resource import Resource +from client.types import PaginatedResponse, Response +from client.types.transactions import TransactionResponse +from client.types.votes import VoteQuery, VotesQuery class Votes(Resource): - def all(self, query={}): + def all(self, query: Optional[VotesQuery] = None) -> PaginatedResponse[TransactionResponse]: return self.with_endpoint('api').request_get('votes', query) - def get(self, vote_id): - return self.with_endpoint('api').request_get(f'votes/{vote_id}') + def get(self, vote_id: str, query: Optional[VoteQuery] = None) -> Response[TransactionResponse]: + return self.with_endpoint('api').request_get(f'votes/{vote_id}', query) diff --git a/client/api/wallets.py b/client/api/wallets.py index b070ec3..9f1e648 100644 --- a/client/api/wallets.py +++ b/client/api/wallets.py @@ -1,45 +1,71 @@ +from typing import Optional + from client.resource import Resource +from client.types import PaginatedResponse, Response +from client.types.transactions import TransactionResponse, TransactionsQuery +from client.types.wallets import WalletResponse, WalletTokensForQuery, WalletTokensQuery, WalletsQuery +from client.types.tokens import TokenActionsResponse, TokenPaginatedResponseResults class Wallets(Resource): - def all(self, query={}): + def all(self, query: Optional[WalletsQuery] = None) -> PaginatedResponse[WalletResponse]: return self.with_endpoint('api').request_get('wallets', query) - def top(self, query={}): + def top(self, query: Optional[WalletsQuery] = None) -> PaginatedResponse[WalletResponse]: return self.with_endpoint('api').request_get('wallets/top', query) - def get(self, wallet_id): + def get(self, wallet_id: str) -> Response[WalletResponse]: return self.with_endpoint('api').request_get( f'wallets/{wallet_id}' ) - def transactions(self, wallet_id, query={}): + def transactions( + self, + wallet_id: str, + query: Optional[TransactionsQuery] = None, + ) -> PaginatedResponse[TransactionResponse]: return self.with_endpoint('api').request_get( f'wallets/{wallet_id}/transactions', query ) - def sent_transactions(self, wallet_id, query={}): + def sent_transactions( + self, + wallet_id: str, + query: Optional[TransactionsQuery] = None, + ) -> PaginatedResponse[TransactionResponse]: return self.with_endpoint('api').request_get( f'wallets/{wallet_id}/transactions/sent', query ) - def received_transactions(self, wallet_id, query={}): + def received_transactions( + self, + wallet_id: str, + query: Optional[TransactionsQuery] = None, + ) -> PaginatedResponse[TransactionResponse]: return self.with_endpoint('api').request_get( f'wallets/{wallet_id}/transactions/received', query ) - def votes(self, wallet_id, query={}): + def votes( + self, + wallet_id: str, + query: Optional[TransactionsQuery] = None, + ) -> PaginatedResponse[TransactionResponse]: return self.with_endpoint('api').request_get( f'wallets/{wallet_id}/votes', query ) - def tokens(self, wallet_id, query={}): + def tokens_for( + self, + address: str, + query: Optional[WalletTokensForQuery] = None, + ) -> TokenPaginatedResponseResults[TokenActionsResponse]: return self.with_endpoint('api').request_get( - f'wallets/{wallet_id}/tokens', query + f'wallets/{address}/tokens', query ) - def tokens_for(self, query={}): + def tokens(self, query: Optional[WalletTokensQuery] = None) -> TokenPaginatedResponseResults[TokenActionsResponse]: return self.with_endpoint('api').request_get( 'wallets/tokens', query ) diff --git a/client/types/__init__.py b/client/types/__init__.py new file mode 100644 index 0000000..c6b1198 --- /dev/null +++ b/client/types/__init__.py @@ -0,0 +1,31 @@ +from typing import Generic, TypeVar, TypedDict + + +T = TypeVar('T') + + +class PaginatedQuery(TypedDict, total=False): + page: int + limit: int + offset: int + + +class ResponseMeta(TypedDict): + totalCountIsEstimate: bool + count: int + first: str + last: str + next: str | None + pageCount: int + previous: str | None + self: str + totalCount: int + + +class Response(Generic[T]): + data: T + + +class PaginatedResponse(Generic[T]): + meta: ResponseMeta + data: list[T] diff --git a/client/types/api_nodes.py b/client/types/api_nodes.py new file mode 100644 index 0000000..dc2e22b --- /dev/null +++ b/client/types/api_nodes.py @@ -0,0 +1,15 @@ +from typing import TypedDict + + +class ApiNodeResponse(TypedDict): + url: str + version: str + height: int + latency: int + status: str + + +class ApiNodesQuery(TypedDict, total=False): + ip: str + orderBy: str + version: str diff --git a/client/types/blockchain.py b/client/types/blockchain.py new file mode 100644 index 0000000..b73a1db --- /dev/null +++ b/client/types/blockchain.py @@ -0,0 +1,11 @@ +from typing import TypedDict + + +class BlockchainBlock(TypedDict): + hash: str + number: int + + +class BlockchainResponse(TypedDict): + block: BlockchainBlock + supply: str diff --git a/client/types/blocks.py b/client/types/blocks.py new file mode 100644 index 0000000..85192a2 --- /dev/null +++ b/client/types/blocks.py @@ -0,0 +1,69 @@ +from typing import TypedDict + +from client.types import PaginatedQuery +from client.types.transactions import Transaction + + +class Block(TypedDict): + hash: str + round: int + number: int + reward: str + version: int + fee: str + stateRoot: str + timestamp: str + transactionsRoot: str + amount: str + gasUsed: int + transactions: list[Transaction] + payloadSize: int + parentHash: str + publicKey: str + proposer: str + transactionCount: int + + +class BlockResponse(TypedDict, total=False): + hash: str + number: int + confirmations: int + amount: str + fee: str + reward: str + total: str + proposer: str + publicKey: str + username: str + transactionsRoot: str + payloadSize: int + parentHash: str + signature: str + timestamp: str + transactionsCount: int + version: int + + +# Functional form required: keys contain dots (e.g. 'height.from') which are not valid Python identifiers +BlocksQuery = TypedDict( + 'BlocksQuery', + { + 'page': int, + 'limit': int, + 'offset': int, + 'transform': bool, + 'orderBy': str, + 'id': str, + 'number': int, + 'height.from': int, + 'height.to': int, + 'timestamp': int, + 'timestamp.from': int, + 'timestamp.to': int, + }, + total=False, +) + + +class BlockTransactionsQuery(PaginatedQuery, total=False): + orderBy: str diff --git a/client/types/commits.py b/client/types/commits.py new file mode 100644 index 0000000..ebcb4c7 --- /dev/null +++ b/client/types/commits.py @@ -0,0 +1,7 @@ +from typing import TypedDict + + +class CommitResponse(TypedDict): + blockNumber: str + signature: str + validators: list[str] diff --git a/client/types/contracts.py b/client/types/contracts.py new file mode 100644 index 0000000..5fad7fc --- /dev/null +++ b/client/types/contracts.py @@ -0,0 +1,15 @@ +from typing import Any, TypedDict + + +class Contract(TypedDict): + activeImplementation: str + address: str + implementations: list[str] + proxy: str + + +ContractResponse = dict[str, Contract] + + +class ContractAbiResponse(TypedDict): + abi: list[Any] diff --git a/client/types/evm.py b/client/types/evm.py new file mode 100644 index 0000000..14f170e --- /dev/null +++ b/client/types/evm.py @@ -0,0 +1,13 @@ +from typing import Literal, TypedDict + + +PayloadData = dict[str, str | int | float] + +BlockParameter = Literal["earliest", "latest", "safe", "finalized", "pending"] + + +class EvmBodyPartialParams(TypedDict, total=False): + jsonrpc: str + method: str + params: list[PayloadData] | list[PayloadData | BlockParameter | str] + id: int | float | None diff --git a/client/types/node.py b/client/types/node.py new file mode 100644 index 0000000..b8fa39a --- /dev/null +++ b/client/types/node.py @@ -0,0 +1,166 @@ +from typing import TypedDict + +from client.types.blocks import Block + + +class NodeStatusResponse(TypedDict): + blocksCount: int + now: int + synced: bool + timestamp: int + + +class NodeSyncingResponse(TypedDict): + blocks: int + blockNumber: int + id: int + syncing: bool + + +class NodeConfigurationTransactionPoolDynamicFees(TypedDict): + enabled: bool + + +class NodeConfigurationTransactionPool(TypedDict): + dynamicFees: NodeConfigurationTransactionPoolDynamicFees + + +class NodeConfigurationCore(TypedDict): + version: str + + +class NativeGasLimits(TypedDict, total=False): + vote: int + transfer: int + multiPayment: int + multiSignature: int + usernameResignation: int + usernameRegistration: int + validatorResignation: int + validatorRegistration: int + + +class ConstantGas(TypedDict, total=False): + minimumGasFee: int + maximumGasLimit: int + minimumGasLimit: int + nativeGasLimits: NativeGasLimits + nativeFeeMultiplier: int + + +class StaticFees(TypedDict, total=False): + vote: int + transfer: int + multiPayment: int + multiSignature: int + usernameResignation: int + usernameRegistration: int + validatorResignation: int + validatorRegistration: int + + +class ConstantFees(TypedDict, total=False): + staticFees: StaticFees + + +class ConstantBlock(TypedDict, total=False): + version: int + maxPayload: int + maxGasLimit: int + maxTransactions: int + + +class ConstantAddress(TypedDict, total=False): + keccak256: bool + + +class ConstantSatoshi(TypedDict, total=False): + decimals: int + denomination: int + + +class ConfigurationTimeouts(TypedDict): + blockTime: int + tolerance: int + stageTimeout: int + blockPrepareTime: int + stageTimeoutIncrease: int + + +class Constant(TypedDict, total=False): + gas: ConstantGas + fees: ConstantFees + block: ConstantBlock + epoch: str + height: int + reward: str + address: ConstantAddress + evmSpec: str + satoshi: ConstantSatoshi + timeouts: ConfigurationTimeouts + activeValidators: int + multiPaymentLimit: int + vendorFieldLength: int + + +class NodeConfigurationResponse(TypedDict): + constants: Constant + core: NodeConfigurationCore + explorer: str + nethash: str + ports: dict[str, int] + slip44: int + symbol: str + token: str + transactionPool: NodeConfigurationTransactionPool + version: int + wif: int + + +class NetworkClient(TypedDict): + token: str + symbol: str + explorer: str + + +class Network(TypedDict): + wif: int + name: str + client: NetworkClient + slip44: int + chainId: int + nethash: str + pubKeyHash: int + messagePrefix: str + + +class GenesisBlockProof(TypedDict): + round: int + signature: str + validators: list + + +class GenesisBlock(TypedDict): + block: Block + proof: GenesisBlockProof + serialized: str + + +class NodeCryptoResponse(TypedDict): + network: Network + milestones: list[Constant] + genesisBlock: GenesisBlock + + +class TransactionTypeFee(TypedDict): + avg: str + max: str + min: str + sum: str + + +NodeFeesResponse = dict[str, TransactionTypeFee] + + +class NodeFeesQuery(TypedDict, total=False): + days: int diff --git a/client/types/peers.py b/client/types/peers.py new file mode 100644 index 0000000..c6e3181 --- /dev/null +++ b/client/types/peers.py @@ -0,0 +1,25 @@ +from typing import TypedDict + +from client.types import PaginatedQuery + + +class Plugin(TypedDict): + enabled: bool + estimateTotalCount: bool + port: int + + +class PeerResponse(TypedDict): + blockNumber: int + ip: str + latency: int + plugins: dict[str, Plugin] + port: int + ports: dict[str, int] + version: str + + +class PeersQuery(PaginatedQuery, total=False): + ip: str + orderBy: str + version: str diff --git a/client/types/receipts.py b/client/types/receipts.py new file mode 100644 index 0000000..e08bac8 --- /dev/null +++ b/client/types/receipts.py @@ -0,0 +1,54 @@ +from typing import Literal, TypedDict + + +class ReceiptLog(TypedDict): + data: str + topics: list[str] + address: str + + +class ReceiptResponse(TypedDict): + transactionHash: str + status: Literal[1, 0] + gasUsed: int + gasRefunded: int + contractAddress: None + logs: list[ReceiptLog] + output: str + + +# Functional form required: keys include 'from' which is a reserved Python keyword +ReceiptsQuery = TypedDict( + 'ReceiptsQuery', + { + 'page': int, + 'limit': int, + 'offset': int, + 'from': str, + 'to': str, + 'fullReceipt': bool, + 'includeTokens': bool, + 'transactionHash': str, + }, + total=False, +) + + +class ReceiptQuery(TypedDict, total=False): + fullReceipt: bool + includeTokens: bool + + +# Functional form required: keys include 'from' which is a reserved Python keyword +ReceiptContractsQuery = TypedDict( + 'ReceiptContractsQuery', + { + 'page': int, + 'limit': int, + 'offset': int, + 'from': str, + 'fullReceipt': bool, + 'includeTokens': bool, + }, + total=False, +) diff --git a/client/types/rounds.py b/client/types/rounds.py new file mode 100644 index 0000000..df78ee3 --- /dev/null +++ b/client/types/rounds.py @@ -0,0 +1,8 @@ +from typing import TypedDict + + +class RoundResponse(TypedDict): + round: str + roundHeight: str + validators: list[str] + votes: list[str] diff --git a/client/types/tokens.py b/client/types/tokens.py new file mode 100644 index 0000000..1580020 --- /dev/null +++ b/client/types/tokens.py @@ -0,0 +1,120 @@ +from typing import Generic, List, TypeVar, TypedDict + +from client.types import PaginatedQuery, ResponseMeta + +T = TypeVar('T') + + +class TokenResponse(TypedDict): + address: str + decimals: int + deploymentHash: str + name: str + totalSupply: str + + +class TokenAddressesResponse(TypedDict): + addresses: dict[str, str] + decimals: int + name: str + supply: str + symbol: str + token: str + + +class TokenActionToken(TypedDict): + address: str + name: str + symbol: str + decimals: int + + +# Functional form required: keys include 'from' which is a reserved Python keyword +TokenActionsResponse = TypedDict( + 'TokenActionsResponse', + { + 'transactionHash': str, + 'from': str, + 'to': str, + 'value': str, + 'functionSig': str, + 'blockNumber': str, + 'timestamp': str, + 'token': TokenActionToken, + }, +) + + +class TokenWhitelistResponse(TypedDict): + address: str + comment: str + createdAt: str + + +class TokenAddressHoldersResponse(TypedDict): + address: str + balance: int + tokenAddress: str + + +class TokenPaginatedResponseData(Generic[T]): + data: T + + +class TokenPaginatedResponseResults(Generic[T]): + meta: ResponseMeta + results: list[T] + + +class TokensQuery(PaginatedQuery, total=False): + ignoreWhitelist: bool + name: str + whitelist: List[str] + + +# Functional form required: keys include 'from' which is a reserved Python keyword +TokenLookupQuery = TypedDict( + 'TokenLookupQuery', + { + 'page': int, + 'limit': int, + 'offset': int, + 'from': str, + 'to': str, + 'transactionHash': str, + }, + total=False, +) + +# Functional form required: keys include 'from' which is a reserved Python keyword +TokenTransfersQuery = TypedDict( + 'TokenTransfersQuery', + { + 'page': int, + 'limit': int, + 'offset': int, + 'from': str, + 'to': str, + 'transactionHash': str, + 'addresses': List[str], + 'ignoreWhitelist': bool, + 'whitelist': List[str], + }, + total=False, +) + +# Functional form required: keys include 'from' which is a reserved Python keyword +TokenApprovalsQuery = TypedDict( + 'TokenApprovalsQuery', + { + 'page': int, + 'limit': int, + 'offset': int, + 'from': str, + 'to': str, + 'transactionHash': str, + 'addresses': List[str], + 'whitelist': List[str], + }, + total=False, +) diff --git a/client/types/transactions.py b/client/types/transactions.py new file mode 100644 index 0000000..2ecb06c --- /dev/null +++ b/client/types/transactions.py @@ -0,0 +1,119 @@ +from typing import List, TypedDict + +from client.types import PaginatedQuery + + +# Functional form required: keys include 'from' which is a reserved Python keyword +Transaction = TypedDict( + 'Transaction', + { + 'hash': str, + 'fee': str, + 'type': int, + 'nonce': str, + 'value': str, + 'network': int, + 'version': int, + 'sequence': int, + 'signature': str, + 'typeGroup': int, + 'expiration': int, + 'to': str, + 'senderPublicKey': str, + 'from': str, + }, +) + + +class TransactionReceipt(TypedDict): + gasRefunded: int + gasUsed: int + success: bool + + +# Functional form required: keys include 'from' which is a reserved Python keyword +TransactionResponse = TypedDict( + 'TransactionResponse', + { + 'hash': str, + 'value': str, + 'blockNumber': str, + 'confirmations': int, + 'data': str, + 'gas': str, + 'gasPrice': str, + 'nonce': str, + 'to': str, + 'from': str, + 'senderPublicKey': str, + 'signature': str, + 'timestamp': str, + 'receipt': TransactionReceipt, + }, +) + + +class TransactionConfigurationTransactionPool(TypedDict): + maxTransactionAge: int + maxTransactionBytes: int + maxTransactionsInPool: int + maxTransactionsPerRequest: int + maxTransactionsPerSender: int + + +class TransactionConfigurationCore(TypedDict): + version: str + + +class TransactionConfigurationResponse(TypedDict): + core: TransactionConfigurationCore + height: int + transactionPool: TransactionConfigurationTransactionPool + + +class TransactionCreateResponse(TypedDict): + accept: list[int] + broadcast: list[int] + excess: list[int] + invalid: list[int] + + +# Functional form required: keys include 'from' which is a reserved Python keyword +TransactionsQuery = TypedDict( + 'TransactionsQuery', + { + 'page': int, + 'limit': int, + 'offset': int, + 'address': str, + 'asset': str, + 'blockHash': str, + 'from': str, + 'gasPrice': int, + 'hash': str, + 'nonce': int, + 'senderId': str, + 'senderPublicKey': str, + 'timestamp': int, + 'to': str, + 'transactionIndex': int, + 'value': int, + 'fullReceipt': bool, + 'includeTokens': bool, + 'orderBy': str, + }, + total=False, +) + + +class UnconfirmedTransactionsQuery(PaginatedQuery, total=False): + orderBy: str + + +class TransactionGetQuery(TypedDict, total=False): + fullReceipt: bool + includeTokens: bool + + +class TransactionCreateParams(TypedDict): + transactions: List[str] diff --git a/client/types/validators.py b/client/types/validators.py new file mode 100644 index 0000000..59f2abd --- /dev/null +++ b/client/types/validators.py @@ -0,0 +1,40 @@ +from typing import TypedDict + + +# Functional form required: keys contain dots (e.g. 'blocks.last.hash') which are not valid Python identifiers +ValidatorsQuery = TypedDict( + 'ValidatorsQuery', + { + 'page': int, + 'limit': int, + 'offset': int, + 'address': str, + 'attributes': str, + 'blocks.last.hash': str, + 'blocks.last.number': int, + 'blocks.produced': int, + 'forged.fees': int, + 'forged.fees.from': int, + 'forged.fees.to': int, + 'forged.rewards': int, + 'forged.rewards.from': int, + 'forged.rewards.to': int, + 'forged.total': int, + 'forged.total.from': int, + 'forged.total.to': int, + 'isResigned': bool, + 'production.approval': int, + 'production.approval.from': int, + 'production.approval.to': int, + 'publicKey': str, + 'rank': int, + 'rank.from': int, + 'rank.to': int, + 'username': str, + 'votes': int, + 'votes.from': int, + 'votes.to': int, + 'orderBy': str, + }, + total=False, +) diff --git a/client/types/votes.py b/client/types/votes.py new file mode 100644 index 0000000..08c38b8 --- /dev/null +++ b/client/types/votes.py @@ -0,0 +1,32 @@ +from typing import TypedDict + + +# Functional form required: keys include 'from' which is a reserved Python keyword +VotesQuery = TypedDict( + 'VotesQuery', + { + 'page': int, + 'limit': int, + 'offset': int, + 'address': str, + 'blockHash': str, + 'data': str, + 'from': str, + 'gasPrice': int, + 'hash': str, + 'nonce': int, + 'senderId': str, + 'senderPublicKey': str, + 'timestamp': int, + 'to': str, + 'transactionIndex': int, + 'value': int, + 'fullReceipt': bool, + 'orderBy': str, + }, + total=False, +) + + +class VoteQuery(TypedDict, total=False): + fullReceipt: bool diff --git a/client/types/wallets.py b/client/types/wallets.py new file mode 100644 index 0000000..2d29f5b --- /dev/null +++ b/client/types/wallets.py @@ -0,0 +1,71 @@ +from typing import List, TypedDict + +from client.types import PaginatedQuery + + +class ValidatorLastBlock(TypedDict): + id: str + height: int + timestamp: int + + +class WalletAttributes(TypedDict, total=False): + username: str + vote: str + validatorRank: int + validatorApproval: int + validatorResigned: bool + validatorLastBlock: ValidatorLastBlock + validatorPublicKey: str + validatorForgedFees: str + validatorForgedTotal: str + validatorVoteBalance: str + validatorVotersCount: int + validatorForgedRewards: str + validatorProducedBlocks: int + + +class WalletResponse(TypedDict): + address: str + publicKey: str + balance: str + nonce: str + attributes: WalletAttributes + updated_at: str + tokenCount: int + + +# Functional form required: keys contain dots (e.g. 'balance.from') which are not valid Python identifiers +WalletsQuery = TypedDict( + 'WalletsQuery', + { + 'page': int, + 'limit': int, + 'offset': int, + 'address': str, + 'publicKey': str, + 'balance': int, + 'balance.from': int, + 'balance.to': int, + 'nonce': int, + 'nonce.from': int, + 'nonce.to': int, + 'attributes': str, + 'orderBy': str, + }, + total=False, +) + + +class WalletTokensForQuery(TypedDict, total=False): + ignoreWhitelist: bool + minBalance: int + name: str + whitelist: List[str] + + +class WalletTokensQuery(PaginatedQuery, total=False): + addresses: List[str] + ignoreWhitelist: bool + minBalance: int + whitelist: List[str] diff --git a/tests/api/test_blocks.py b/tests/api/test_blocks.py index 6073d83..da7f8df 100644 --- a/tests/api/test_blocks.py +++ b/tests/api/test_blocks.py @@ -32,7 +32,7 @@ def test_all_calls_correct_url_with_params(): 'page': 5, 'limit': 69, 'orderBy': 'timestamp.epoch', - 'height': 6838329, + 'number': 6838329, }) assert len(responses.calls) == 1 url = responses.calls[0].request.url @@ -40,7 +40,7 @@ def test_all_calls_correct_url_with_params(): assert 'page=5' in url assert 'limit=69' in url assert 'orderBy=timestamp.epoch' in url - assert 'height=6838329' in url + assert 'number=6838329' in url def test_get_calls_correct_url(): diff --git a/tests/api/test_commits.py b/tests/api/test_commits.py index dc50112..28c88e3 100644 --- a/tests/api/test_commits.py +++ b/tests/api/test_commits.py @@ -12,6 +12,6 @@ def test_show_calls_correct_url(): ) client = ArkClient('http://127.0.0.1:4002/api') - client.commits.show(1) + client.commits.get(1) assert len(responses.calls) == 1 assert responses.calls[0].request.url == 'http://127.0.0.1:4002/api/commits/1' diff --git a/tests/api/test_receipts.py b/tests/api/test_receipts.py index c1e20b1..bc16f25 100644 --- a/tests/api/test_receipts.py +++ b/tests/api/test_receipts.py @@ -53,3 +53,52 @@ def test_get_calls_correct_url(): assert responses.calls[0].request.url == ( f'http://127.0.0.1:4002/api/receipts/{transaction_hash}' ) + + +def test_get_calls_correct_url_with_params(): + transaction_hash = '12345' + responses.add( + responses.GET, + f'http://127.0.0.1:4002/api/receipts/{transaction_hash}', + json={'success': True}, + status=200 + ) + + client = ArkClient('http://127.0.0.1:4002/api') + client.receipts.get(transaction_hash, {'format': 'hex'}) + assert len(responses.calls) == 1 + url = responses.calls[0].request.url + assert url.startswith(f'http://127.0.0.1:4002/api/receipts/{transaction_hash}?') + assert 'format=hex' in url + + +def test_contracts_calls_correct_url(): + responses.add( + responses.GET, + 'http://127.0.0.1:4002/api/receipts/contracts', + json={'success': True}, + status=200 + ) + + client = ArkClient('http://127.0.0.1:4002/api') + client.receipts.contracts() + assert len(responses.calls) == 1 + assert responses.calls[0].request.url == ( + 'http://127.0.0.1:4002/api/receipts/contracts' + ) + + +def test_contracts_calls_correct_url_with_params(): + responses.add( + responses.GET, + 'http://127.0.0.1:4002/api/receipts/contracts', + json={'success': True}, + status=200 + ) + + client = ArkClient('http://127.0.0.1:4002/api') + client.receipts.contracts({'status': 'success'}) + assert len(responses.calls) == 1 + url = responses.calls[0].request.url + assert url.startswith('http://127.0.0.1:4002/api/receipts/contracts?') + assert 'status=success' in url diff --git a/tests/api/test_tokens.py b/tests/api/test_tokens.py index 3aa6ec5..7505f96 100644 --- a/tests/api/test_tokens.py +++ b/tests/api/test_tokens.py @@ -53,7 +53,7 @@ def test_get_calls_correct_url(): ) -def test_holders_calls_correct_url(): +def test_holders_for_calls_correct_url(): address = '0x1234567890abcdef' responses.add( responses.GET, @@ -63,65 +63,82 @@ def test_holders_calls_correct_url(): ) client = ArkClient('http://127.0.0.1:4002/api') - client.tokens.holders(address) + client.tokens.holders_for(address) assert len(responses.calls) == 1 assert responses.calls[0].request.url == ( 'http://127.0.0.1:4002/api/tokens/0x1234567890abcdef/holders' ) -def test_holders_calls_correct_url_with_params(): +def test_transfers_for_calls_correct_url(): address = '0x1234567890abcdef' responses.add( responses.GET, - 'http://127.0.0.1:4002/api/tokens/{}/holders'.format(address), + 'http://127.0.0.1:4002/api/tokens/{}/transfers'.format(address), + json={'success': True}, + status=200 + ) + + client = ArkClient('http://127.0.0.1:4002/api') + client.tokens.transfers_for(address) + assert len(responses.calls) == 1 + assert responses.calls[0].request.url == ( + 'http://127.0.0.1:4002/api/tokens/0x1234567890abcdef/transfers' + ) + + +def test_transfers_for_calls_correct_url_with_params(): + address = '0x1234567890abcdef' + responses.add( + responses.GET, + 'http://127.0.0.1:4002/api/tokens/{}/transfers'.format(address), json={'success': True}, status=200 ) client = ArkClient('http://127.0.0.1:4002/api') - client.tokens.holders(address, {'page': 3, 'limit': 50}) + client.tokens.transfers_for(address, {'page': 2, 'limit': 25}) assert len(responses.calls) == 1 url = responses.calls[0].request.url assert url.startswith( - 'http://127.0.0.1:4002/api/tokens/0x1234567890abcdef/holders?' + 'http://127.0.0.1:4002/api/tokens/0x1234567890abcdef/transfers?' ) - assert 'page=3' in url - assert 'limit=50' in url + assert 'page=2' in url + assert 'limit=25' in url -def test_transfers_by_token_calls_correct_url(): +def test_approvals_for_calls_correct_url(): address = '0x1234567890abcdef' responses.add( responses.GET, - 'http://127.0.0.1:4002/api/tokens/{}/transfers'.format(address), + 'http://127.0.0.1:4002/api/tokens/{}/approvals'.format(address), json={'success': True}, status=200 ) client = ArkClient('http://127.0.0.1:4002/api') - client.tokens.transfers_by_token(address) + client.tokens.approvals_for(address) assert len(responses.calls) == 1 assert responses.calls[0].request.url == ( - 'http://127.0.0.1:4002/api/tokens/0x1234567890abcdef/transfers' + 'http://127.0.0.1:4002/api/tokens/0x1234567890abcdef/approvals' ) -def test_transfers_by_token_calls_correct_url_with_params(): +def test_approvals_for_calls_correct_url_with_params(): address = '0x1234567890abcdef' responses.add( responses.GET, - 'http://127.0.0.1:4002/api/tokens/{}/transfers'.format(address), + 'http://127.0.0.1:4002/api/tokens/{}/approvals'.format(address), json={'success': True}, status=200 ) client = ArkClient('http://127.0.0.1:4002/api') - client.tokens.transfers_by_token(address, {'page': 2, 'limit': 25}) + client.tokens.approvals_for(address, {'page': 2, 'limit': 25}) assert len(responses.calls) == 1 url = responses.calls[0].request.url assert url.startswith( - 'http://127.0.0.1:4002/api/tokens/0x1234567890abcdef/transfers?' + 'http://127.0.0.1:4002/api/tokens/0x1234567890abcdef/approvals?' ) assert 'page=2' in url assert 'limit=25' in url @@ -160,3 +177,73 @@ def test_transfers_calls_correct_url_with_params(): ) assert 'page=1' in url assert 'limit=10' in url + + +def test_approvals_calls_correct_url(): + responses.add( + responses.GET, + 'http://127.0.0.1:4002/api/tokens/approvals', + json={'success': True}, + status=200 + ) + + client = ArkClient('http://127.0.0.1:4002/api') + client.tokens.approvals() + assert len(responses.calls) == 1 + assert responses.calls[0].request.url == ( + 'http://127.0.0.1:4002/api/tokens/approvals' + ) + + +def test_approvals_calls_correct_url_with_params(): + responses.add( + responses.GET, + 'http://127.0.0.1:4002/api/tokens/approvals', + json={'success': True}, + status=200 + ) + + client = ArkClient('http://127.0.0.1:4002/api') + client.tokens.approvals({'page': 1, 'limit': 10}) + assert len(responses.calls) == 1 + url = responses.calls[0].request.url + assert url.startswith( + 'http://127.0.0.1:4002/api/tokens/approvals?' + ) + assert 'page=1' in url + assert 'limit=10' in url + + +def test_whitelist_calls_correct_url(): + responses.add( + responses.GET, + 'http://127.0.0.1:4002/api/tokens/whitelist', + json={'success': True}, + status=200 + ) + + client = ArkClient('http://127.0.0.1:4002/api') + client.tokens.whitelist() + assert len(responses.calls) == 1 + assert responses.calls[0].request.url == ( + 'http://127.0.0.1:4002/api/tokens/whitelist' + ) + + +def test_whitelist_calls_correct_url_with_params(): + responses.add( + responses.GET, + 'http://127.0.0.1:4002/api/tokens/whitelist', + json={'success': True}, + status=200 + ) + + client = ArkClient('http://127.0.0.1:4002/api') + client.tokens.whitelist({'page': 3, 'limit': 50}) + assert len(responses.calls) == 1 + url = responses.calls[0].request.url + assert url.startswith( + 'http://127.0.0.1:4002/api/tokens/whitelist?' + ) + assert 'page=3' in url + assert 'limit=50' in url diff --git a/tests/api/test_transactions.py b/tests/api/test_transactions.py index 25cc196..b0d4fe1 100644 --- a/tests/api/test_transactions.py +++ b/tests/api/test_transactions.py @@ -87,28 +87,36 @@ def test_get_calls_correct_url(): def test_all_unconfirmed_calls_correct_url(): responses.add( responses.GET, - 'http://127.0.0.1:4002/api/transactions/unconfirmed', + 'http://127.0.0.1:4002/tx/api/transactions/unconfirmed', json={'success': True}, status=200 ) - client = ArkClient('http://127.0.0.1:4002/api') + client = ArkClient({ + 'api': 'http://127.0.0.1:4002/api', + 'transactions': 'http://127.0.0.1:4002/tx/api', + 'evm': None, + }) client.transactions.all_unconfirmed() assert len(responses.calls) == 1 assert responses.calls[0].request.url == ( - 'http://127.0.0.1:4002/api/transactions/unconfirmed' + 'http://127.0.0.1:4002/tx/api/transactions/unconfirmed' ) def test_all_unconfirmed_calls_correct_url_with_params(): responses.add( responses.GET, - 'http://127.0.0.1:4002/api/transactions/unconfirmed', + 'http://127.0.0.1:4002/tx/api/transactions/unconfirmed', json={'success': True}, status=200 ) - client = ArkClient('http://127.0.0.1:4002/api') + client = ArkClient({ + 'api': 'http://127.0.0.1:4002/api', + 'transactions': 'http://127.0.0.1:4002/tx/api', + 'evm': None, + }) client.transactions.all_unconfirmed({ 'page': 5, 'limit': 69, @@ -117,7 +125,7 @@ def test_all_unconfirmed_calls_correct_url_with_params(): assert len(responses.calls) == 1 url = responses.calls[0].request.url assert url.startswith( - 'http://127.0.0.1:4002/api/transactions/unconfirmed?' + 'http://127.0.0.1:4002/tx/api/transactions/unconfirmed?' ) assert 'page=5' in url assert 'limit=69' in url @@ -129,18 +137,22 @@ def test_get_unconfirmed_calls_correct_url(): responses.add( responses.GET, - 'http://127.0.0.1:4002/api/transactions/unconfirmed/{}'.format( + 'http://127.0.0.1:4002/tx/api/transactions/unconfirmed/{}'.format( transaction_id ), json={'success': True}, status=200 ) - client = ArkClient('http://127.0.0.1:4002/api') + client = ArkClient({ + 'api': 'http://127.0.0.1:4002/api', + 'transactions': 'http://127.0.0.1:4002/tx/api', + 'evm': None, + }) client.transactions.get_unconfirmed(transaction_id) assert len(responses.calls) == 1 assert responses.calls[0].request.url == ( - 'http://127.0.0.1:4002/api/transactions/unconfirmed/12345' + 'http://127.0.0.1:4002/tx/api/transactions/unconfirmed/12345' ) diff --git a/tests/api/test_wallets.py b/tests/api/test_wallets.py index c9b0ed2..e6f602a 100644 --- a/tests/api/test_wallets.py +++ b/tests/api/test_wallets.py @@ -257,7 +257,7 @@ def test_votes_calls_correct_url_with_params(): assert 'limit=69' in url -def test_tokens_calls_correct_url(): +def test_tokens_for_calls_correct_url(): wallet_id = '12345' responses.add( responses.GET, @@ -267,14 +267,14 @@ def test_tokens_calls_correct_url(): ) client = ArkClient('http://127.0.0.1:4002/api') - client.wallets.tokens(wallet_id) + client.wallets.tokens_for(wallet_id) assert len(responses.calls) == 1 assert responses.calls[0].request.url == ( 'http://127.0.0.1:4002/api/wallets/12345/tokens' ) -def test_tokens_calls_correct_url_with_params(): +def test_tokens_for_calls_correct_url_with_params(): wallet_id = '12345' responses.add( responses.GET, @@ -284,7 +284,7 @@ def test_tokens_calls_correct_url_with_params(): ) client = ArkClient('http://127.0.0.1:4002/api') - client.wallets.tokens(wallet_id, {'page': 5, 'limit': 69}) + client.wallets.tokens_for(wallet_id, {'page': 5, 'limit': 69}) assert len(responses.calls) == 1 url = responses.calls[0].request.url assert url.startswith( @@ -294,7 +294,7 @@ def test_tokens_calls_correct_url_with_params(): assert 'limit=69' in url -def test_tokens_for_calls_correct_url(): +def test_tokens_calls_correct_url(): responses.add( responses.GET, 'http://127.0.0.1:4002/api/wallets/tokens', @@ -303,9 +303,7 @@ def test_tokens_for_calls_correct_url(): ) client = ArkClient('http://127.0.0.1:4002/api') - client.wallets.tokens_for({ - 'addresses': '0xabc,0xdef', - }) + client.wallets.tokens({'addresses': '0xabc,0xdef'}) assert len(responses.calls) == 1 url = responses.calls[0].request.url assert url.startswith( @@ -314,7 +312,7 @@ def test_tokens_for_calls_correct_url(): assert 'addresses=0xabc%2C0xdef' in url -def test_tokens_for_calls_correct_url_with_params(): +def test_tokens_calls_correct_url_with_params(): responses.add( responses.GET, 'http://127.0.0.1:4002/api/wallets/tokens', @@ -323,7 +321,7 @@ def test_tokens_for_calls_correct_url_with_params(): ) client = ArkClient('http://127.0.0.1:4002/api') - client.wallets.tokens_for({ + client.wallets.tokens({ 'addresses': '0xabc,0xdef', 'page': 2, 'limit': 50,