cdp-sdk 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. cdp/__init__.py +27 -0
  2. cdp/__version__.py +1 -0
  3. cdp/address.py +107 -0
  4. cdp/api_clients.py +148 -0
  5. cdp/asset.py +165 -0
  6. cdp/balance.py +79 -0
  7. cdp/balance_map.py +75 -0
  8. cdp/cdp.py +117 -0
  9. cdp/cdp_api_client.py +180 -0
  10. cdp/client/__init__.py +147 -0
  11. cdp/client/api/__init__.py +20 -0
  12. cdp/client/api/addresses_api.py +2476 -0
  13. cdp/client/api/assets_api.py +277 -0
  14. cdp/client/api/balance_history_api.py +357 -0
  15. cdp/client/api/contract_events_api.py +430 -0
  16. cdp/client/api/contract_invocations_api.py +1164 -0
  17. cdp/client/api/external_addresses_api.py +1127 -0
  18. cdp/client/api/networks_api.py +247 -0
  19. cdp/client/api/server_signers_api.py +1525 -0
  20. cdp/client/api/smart_contracts_api.py +1097 -0
  21. cdp/client/api/stake_api.py +1449 -0
  22. cdp/client/api/trades_api.py +1144 -0
  23. cdp/client/api/transfers_api.py +1144 -0
  24. cdp/client/api/users_api.py +232 -0
  25. cdp/client/api/validators_api.py +615 -0
  26. cdp/client/api/wallet_stake_api.py +856 -0
  27. cdp/client/api/wallets_api.py +1203 -0
  28. cdp/client/api/webhooks_api.py +988 -0
  29. cdp/client/api_client.py +694 -0
  30. cdp/client/api_response.py +21 -0
  31. cdp/client/configuration.py +457 -0
  32. cdp/client/exceptions.py +194 -0
  33. cdp/client/models/__init__.py +114 -0
  34. cdp/client/models/address.py +95 -0
  35. cdp/client/models/address_balance_list.py +100 -0
  36. cdp/client/models/address_historical_balance_list.py +98 -0
  37. cdp/client/models/address_list.py +100 -0
  38. cdp/client/models/address_transaction_list.py +98 -0
  39. cdp/client/models/asset.py +93 -0
  40. cdp/client/models/balance.py +88 -0
  41. cdp/client/models/broadcast_contract_invocation_request.py +79 -0
  42. cdp/client/models/broadcast_staking_operation_request.py +87 -0
  43. cdp/client/models/broadcast_trade_request.py +85 -0
  44. cdp/client/models/broadcast_transfer_request.py +77 -0
  45. cdp/client/models/build_staking_operation_request.py +97 -0
  46. cdp/client/models/contract_event.py +126 -0
  47. cdp/client/models/contract_event_list.py +98 -0
  48. cdp/client/models/contract_invocation.py +121 -0
  49. cdp/client/models/contract_invocation_list.py +102 -0
  50. cdp/client/models/create_address_request.py +92 -0
  51. cdp/client/models/create_contract_invocation_request.py +94 -0
  52. cdp/client/models/create_payload_signature_request.py +80 -0
  53. cdp/client/models/create_server_signer_request.py +89 -0
  54. cdp/client/models/create_smart_contract_request.py +91 -0
  55. cdp/client/models/create_staking_operation_request.py +87 -0
  56. cdp/client/models/create_trade_request.py +85 -0
  57. cdp/client/models/create_transfer_request.py +99 -0
  58. cdp/client/models/create_wallet_request.py +88 -0
  59. cdp/client/models/create_wallet_request_wallet.py +83 -0
  60. cdp/client/models/create_webhook_request.py +126 -0
  61. cdp/client/models/deploy_smart_contract_request.py +79 -0
  62. cdp/client/models/erc20_transfer_event.py +159 -0
  63. cdp/client/models/erc721_transfer_event.py +158 -0
  64. cdp/client/models/error.py +92 -0
  65. cdp/client/models/ethereum_transaction.py +186 -0
  66. cdp/client/models/ethereum_transaction_access.py +80 -0
  67. cdp/client/models/ethereum_transaction_access_list.py +94 -0
  68. cdp/client/models/ethereum_transaction_flattened_trace.py +137 -0
  69. cdp/client/models/ethereum_validator_metadata.py +127 -0
  70. cdp/client/models/faucet_transaction.py +87 -0
  71. cdp/client/models/feature_set.py +98 -0
  72. cdp/client/models/fetch_historical_staking_balances200_response.py +98 -0
  73. cdp/client/models/fetch_staking_rewards200_response.py +98 -0
  74. cdp/client/models/fetch_staking_rewards_request.py +107 -0
  75. cdp/client/models/get_staking_context_request.py +89 -0
  76. cdp/client/models/historical_balance.py +96 -0
  77. cdp/client/models/network.py +127 -0
  78. cdp/client/models/network_identifier.py +37 -0
  79. cdp/client/models/nft_contract_options.py +78 -0
  80. cdp/client/models/payload_signature.py +107 -0
  81. cdp/client/models/payload_signature_list.py +102 -0
  82. cdp/client/models/seed_creation_event.py +82 -0
  83. cdp/client/models/seed_creation_event_result.py +96 -0
  84. cdp/client/models/server_signer.py +87 -0
  85. cdp/client/models/server_signer_event.py +92 -0
  86. cdp/client/models/server_signer_event_event.py +147 -0
  87. cdp/client/models/server_signer_event_list.py +100 -0
  88. cdp/client/models/server_signer_list.py +102 -0
  89. cdp/client/models/signature_creation_event.py +112 -0
  90. cdp/client/models/signature_creation_event_result.py +102 -0
  91. cdp/client/models/signed_voluntary_exit_message_metadata.py +89 -0
  92. cdp/client/models/smart_contract.py +125 -0
  93. cdp/client/models/smart_contract_list.py +98 -0
  94. cdp/client/models/smart_contract_options.py +147 -0
  95. cdp/client/models/smart_contract_type.py +31 -0
  96. cdp/client/models/sponsored_send.py +119 -0
  97. cdp/client/models/staking_balance.py +112 -0
  98. cdp/client/models/staking_context.py +88 -0
  99. cdp/client/models/staking_context_context.py +106 -0
  100. cdp/client/models/staking_operation.py +133 -0
  101. cdp/client/models/staking_operation_metadata.py +141 -0
  102. cdp/client/models/staking_reward.py +120 -0
  103. cdp/client/models/staking_reward_format.py +31 -0
  104. cdp/client/models/staking_reward_usd_value.py +88 -0
  105. cdp/client/models/token_contract_options.py +87 -0
  106. cdp/client/models/trade.py +137 -0
  107. cdp/client/models/trade_list.py +102 -0
  108. cdp/client/models/transaction.py +147 -0
  109. cdp/client/models/transaction_content.py +133 -0
  110. cdp/client/models/transaction_type.py +30 -0
  111. cdp/client/models/transfer.py +162 -0
  112. cdp/client/models/transfer_list.py +102 -0
  113. cdp/client/models/update_webhook_request.py +107 -0
  114. cdp/client/models/user.py +78 -0
  115. cdp/client/models/validator.py +107 -0
  116. cdp/client/models/validator_details.py +135 -0
  117. cdp/client/models/validator_list.py +98 -0
  118. cdp/client/models/validator_status.py +42 -0
  119. cdp/client/models/wallet.py +120 -0
  120. cdp/client/models/wallet_list.py +100 -0
  121. cdp/client/models/webhook.py +142 -0
  122. cdp/client/models/webhook_event_filter.py +94 -0
  123. cdp/client/models/webhook_event_type.py +33 -0
  124. cdp/client/models/webhook_event_type_filter.py +135 -0
  125. cdp/client/models/webhook_list.py +101 -0
  126. cdp/client/models/webhook_wallet_activity_filter.py +84 -0
  127. cdp/client/py.typed +0 -0
  128. cdp/client/rest.py +222 -0
  129. cdp/errors.py +359 -0
  130. cdp/faucet_transaction.py +44 -0
  131. cdp/py.typed +0 -0
  132. cdp/sponsored_send.py +164 -0
  133. cdp/trade.py +266 -0
  134. cdp/transaction.py +181 -0
  135. cdp/transfer.py +325 -0
  136. cdp/wallet.py +622 -0
  137. cdp/wallet_address.py +191 -0
  138. cdp_sdk-0.0.1.dist-info/LICENSE.md +15 -0
  139. cdp_sdk-0.0.1.dist-info/METADATA +264 -0
  140. cdp_sdk-0.0.1.dist-info/RECORD +142 -0
  141. cdp_sdk-0.0.1.dist-info/WHEEL +5 -0
  142. cdp_sdk-0.0.1.dist-info/top_level.txt +1 -0
cdp/__init__.py ADDED
@@ -0,0 +1,27 @@
1
+ from cdp.__version__ import __version__
2
+ from cdp.address import Address
3
+ from cdp.asset import Asset
4
+ from cdp.balance import Balance
5
+ from cdp.balance_map import BalanceMap
6
+ from cdp.cdp import Cdp
7
+ from cdp.faucet_transaction import FaucetTransaction
8
+ from cdp.sponsored_send import SponsoredSend
9
+ from cdp.trade import Trade
10
+ from cdp.transaction import Transaction
11
+ from cdp.transfer import Transfer
12
+ from cdp.wallet import Wallet
13
+
14
+ __all__ = [
15
+ "__version__",
16
+ "Cdp",
17
+ "Wallet",
18
+ "Asset",
19
+ "Transfer",
20
+ "Address",
21
+ "Transaction",
22
+ "Balance",
23
+ "BalanceMap",
24
+ "FaucetTransaction",
25
+ "Trade",
26
+ "SponsoredSend",
27
+ ]
cdp/__version__.py ADDED
@@ -0,0 +1 @@
1
+ __version__ = "0.0.1"
cdp/address.py ADDED
@@ -0,0 +1,107 @@
1
+ from decimal import Decimal
2
+
3
+ from cdp.asset import Asset
4
+ from cdp.balance import Balance
5
+ from cdp.balance_map import BalanceMap
6
+ from cdp.cdp import Cdp
7
+ from cdp.faucet_transaction import FaucetTransaction
8
+
9
+
10
+ class Address:
11
+ """A class representing an address."""
12
+
13
+ def __init__(self, network_id: str, address_id: str) -> None:
14
+ """Initialize the Address class.
15
+
16
+ Args:
17
+ network_id (str): The network ID.
18
+ address_id (str): The address ID.
19
+
20
+ """
21
+ self._network_id = network_id
22
+ self._id = address_id
23
+
24
+ @property
25
+ def address_id(self) -> str:
26
+ """Get the address ID.
27
+
28
+ Returns:
29
+ str: The address ID.
30
+
31
+ """
32
+ return self._id
33
+
34
+ @property
35
+ def network_id(self) -> str:
36
+ """Get the network ID.
37
+
38
+ Returns:
39
+ str: The network ID.
40
+
41
+ """
42
+ return self._network_id
43
+
44
+ @property
45
+ def can_sign(self) -> bool:
46
+ """Get whether the address can sign.
47
+
48
+ Returns:
49
+ bool: Whether the address can sign.
50
+
51
+ """
52
+ return False
53
+
54
+ def faucet(self, asset_id=None) -> FaucetTransaction:
55
+ """Request faucet funds.
56
+
57
+ Args:
58
+ asset_id (str): The asset ID.
59
+
60
+ Returns:
61
+ FaucetTransaction: The faucet transaction object.
62
+
63
+ """
64
+ model = Cdp.api_clients.external_addresses.request_external_faucet_funds(
65
+ network_id=self.network_id, address_id=self.address_id, asset_id=asset_id
66
+ )
67
+
68
+ return FaucetTransaction(model)
69
+
70
+ def balance(self, asset_id) -> Decimal:
71
+ """Get the balance of the address.
72
+
73
+ Args:
74
+ asset_id (str): The asset ID.
75
+
76
+ Returns:
77
+ Decimal: The balance of the address.
78
+
79
+ """
80
+ model = Cdp.api_clients.external_addresses.get_external_address_balance(
81
+ network_id=self.network_id,
82
+ address_id=self.address_id,
83
+ asset_id=Asset.primary_denomination(asset_id),
84
+ )
85
+
86
+ return Decimal(0) if model is None else Balance.from_model(model, asset_id).amount
87
+
88
+ def balances(self):
89
+ """List balances of the address.
90
+
91
+ Returns:
92
+ BalanceMap: The balances of the address, keyed by asset ID. Ether balances are denominated in ETH.
93
+
94
+ """
95
+ response = Cdp.api_clients.external_addresses.list_external_address_balances(
96
+ network_id=self.network_id, address_id=self.address_id
97
+ )
98
+
99
+ return BalanceMap.from_models(response.data)
100
+
101
+ def __str__(self) -> str:
102
+ """Return a string representation of the Address."""
103
+ return f"Address: (address_id: {self.address_id}, network_id: {self.network_id})"
104
+
105
+ def __repr__(self) -> str:
106
+ """Return a string representation of the Address."""
107
+ return str(self)
cdp/api_clients.py ADDED
@@ -0,0 +1,148 @@
1
+ from cdp.cdp_api_client import CdpApiClient
2
+ from cdp.client.api.addresses_api import AddressesApi
3
+ from cdp.client.api.assets_api import AssetsApi
4
+ from cdp.client.api.external_addresses_api import ExternalAddressesApi
5
+ from cdp.client.api.networks_api import NetworksApi
6
+ from cdp.client.api.trades_api import TradesApi
7
+ from cdp.client.api.transfers_api import TransfersApi
8
+ from cdp.client.api.wallets_api import WalletsApi
9
+
10
+
11
+ class ApiClients:
12
+ """A container class for all API clients used in the Coinbase SDK.
13
+
14
+ This class provides lazy-loaded access to various API clients, ensuring
15
+ that each client is only instantiated when it's first accessed.
16
+
17
+ Attributes:
18
+ _cdp_client (CdpApiClient): The CDP API client used to initialize individual API clients.
19
+ _wallets (Optional[WalletsApi]): The WalletsApi client instance.
20
+ _addresses (Optional[AddressesApi]): The AddressesApi client instance.
21
+ _external_addresses (Optional[ExternalAddressesApi]): The ExternalAddressesApi client instance.
22
+ _transfers (Optional[TransfersApi]): The TransfersApi client instance.
23
+ _networks (Optional[NetworksApi]): The NetworksApi client instance.
24
+ _assets (Optional[AssetsApi]): The AssetsApi client instance.
25
+ _trades (Optional[TradesApi]): The TradesApi client instance.
26
+
27
+ """
28
+
29
+ def __init__(self, cdp_client: CdpApiClient) -> None:
30
+ """Initialize the ApiClients instance.
31
+
32
+ Args:
33
+ cdp_client (CdpApiClient): The CDP API client to use for initializing individual API clients.
34
+
35
+ """
36
+ self._cdp_client: CdpApiClient = cdp_client
37
+ self._wallets: WalletsApi | None = None
38
+ self._addresses: AddressesApi | None = None
39
+ self._external_addresses: ExternalAddressesApi | None = None
40
+ self._transfers: TransfersApi | None = None
41
+ self._networks: NetworksApi | None = None
42
+ self._assets: AssetsApi | None = None
43
+ self._trades: TradesApi | None = None
44
+
45
+ @property
46
+ def wallets(self) -> WalletsApi:
47
+ """Get the WalletsApi client instance.
48
+
49
+ Returns:
50
+ WalletsApi: The WalletsApi client instance.
51
+
52
+ Note:
53
+ This property lazily initializes the WalletsApi client on first access.
54
+
55
+ """
56
+ if self._wallets is None:
57
+ self._wallets = WalletsApi(api_client=self._cdp_client)
58
+ return self._wallets
59
+
60
+ @property
61
+ def addresses(self) -> AddressesApi:
62
+ """Get the AddressesApi client instance.
63
+
64
+ Returns:
65
+ AddressesApi: The AddressesApi client instance.
66
+
67
+ Note:
68
+ This property lazily initializes the AddressesApi client on first access.
69
+
70
+ """
71
+ if self._addresses is None:
72
+ self._addresses = AddressesApi(api_client=self._cdp_client)
73
+ return self._addresses
74
+
75
+ @property
76
+ def external_addresses(self) -> ExternalAddressesApi:
77
+ """Get the ExternalAddressesApi client instance.
78
+
79
+ Returns:
80
+ ExternalAddressesApi: The ExternalAddressesApi client instance.
81
+
82
+ Note:
83
+ This property lazily initializes the ExternalAddressesApi client on first access.
84
+
85
+ """
86
+ if self._external_addresses is None:
87
+ self._external_addresses = ExternalAddressesApi(api_client=self._cdp_client)
88
+ return self._external_addresses
89
+
90
+ @property
91
+ def transfers(self) -> TransfersApi:
92
+ """Get the TransfersApi client instance.
93
+
94
+ Returns:
95
+ TransfersApi: The TransfersApi client instance.
96
+
97
+ Note:
98
+ This property lazily initializes the TransfersApi client on first access.
99
+
100
+ """
101
+ if self._transfers is None:
102
+ self._transfers = TransfersApi(api_client=self._cdp_client)
103
+ return self._transfers
104
+
105
+ @property
106
+ def networks(self) -> NetworksApi:
107
+ """Get the NetworksApi client instance.
108
+
109
+ Returns:
110
+ NetworksApi: The NetworksApi client instance.
111
+
112
+ Note:
113
+ This property lazily initializes the NetworksApi client on first access.
114
+
115
+ """
116
+ if self._networks is None:
117
+ self._networks = NetworksApi(api_client=self._cdp_client)
118
+ return self._networks
119
+
120
+ @property
121
+ def assets(self) -> AssetsApi:
122
+ """Get the AssetsApi client instance.
123
+
124
+ Returns:
125
+ AssetsApi: The AssetsApi client instance.
126
+
127
+ Note:
128
+ This property lazily initializes the AssetsApi client on first access.
129
+
130
+ """
131
+ if self._assets is None:
132
+ self._assets = AssetsApi(api_client=self._cdp_client)
133
+ return self._assets
134
+
135
+ @property
136
+ def trades(self) -> TradesApi:
137
+ """Get the TradesApi client instance.
138
+
139
+ Returns:
140
+ TradesApi: The TradesApi client instance.
141
+
142
+ Note:
143
+ This property lazily initializes the TradesApi client on first access.
144
+
145
+ """
146
+ if self._trades is None:
147
+ self._trades = TradesApi(api_client=self._cdp_client)
148
+ return self._trades
cdp/asset.py ADDED
@@ -0,0 +1,165 @@
1
+ from decimal import Decimal
2
+
3
+ from cdp.cdp import Cdp
4
+ from cdp.client.models.asset import Asset as AssetModel
5
+
6
+ # TODO: Move to constants.py
7
+ GWEI_DECIMALS = 9
8
+
9
+
10
+ class Asset:
11
+ """A class representing an asset."""
12
+
13
+ def __init__(
14
+ self, network_id: str, asset_id: str, contract_address: str, decimals: int
15
+ ) -> None:
16
+ """Initialize the Asset class.
17
+
18
+ Args:
19
+ network_id (str): The network ID.
20
+ asset_id (str): The asset ID.
21
+ contract_address (str): The contract address.
22
+ decimals (int): The number of decimals.
23
+
24
+ """
25
+ self._network_id = network_id
26
+ self._asset_id = asset_id
27
+ self._contract_address = contract_address
28
+ self._decimals = decimals
29
+
30
+ @classmethod
31
+ def from_model(cls, model: AssetModel, asset_id: str | None = None) -> "Asset":
32
+ """Create an Asset instance from a model.
33
+
34
+ Args:
35
+ model (AssetModel): The model representing the asset.
36
+ asset_id (Optional[str]): The asset ID.
37
+
38
+ Returns:
39
+ Asset: The Asset instance.
40
+
41
+ """
42
+ decimals = model.decimals
43
+
44
+ if asset_id and asset_id != model.asset_id:
45
+ match asset_id:
46
+ case "gwei":
47
+ decimals = GWEI_DECIMALS
48
+ case "wei":
49
+ decimals = 0
50
+ case _:
51
+ raise ValueError(f"Unsupported asset ID: {asset_id}")
52
+
53
+ return cls(
54
+ network_id=model.network_id,
55
+ asset_id=model.asset_id,
56
+ contract_address=model.contract_address,
57
+ decimals=decimals,
58
+ )
59
+
60
+ @classmethod
61
+ def fetch(cls, network_id: str, asset_id: str) -> "Asset":
62
+ """Fetch an asset from the API.
63
+
64
+ Args:
65
+ network_id (str): The network ID.
66
+ asset_id (str): The asset ID.
67
+
68
+ Returns:
69
+ Asset: The fetched Asset instance.
70
+
71
+ """
72
+ primary_denomination_asset_id = cls.primary_denomination(asset_id)
73
+
74
+ model = Cdp.api_clients.assets.get_asset(
75
+ network_id=network_id, asset_id=primary_denomination_asset_id
76
+ )
77
+
78
+ return cls.from_model(model, asset_id=asset_id)
79
+
80
+ @staticmethod
81
+ def primary_denomination(asset_id: str) -> str:
82
+ """Get the primary denomination for a given asset ID.
83
+
84
+ Args:
85
+ asset_id (str): The asset ID.
86
+
87
+ Returns:
88
+ str: The primary denomination of the asset.
89
+
90
+ """
91
+ if asset_id in ["wei", "gwei"]:
92
+ return "eth"
93
+ return asset_id
94
+
95
+ @property
96
+ def decimals(self) -> int:
97
+ """Get the number of decimals for the asset.
98
+
99
+ Returns:
100
+ int: The number of decimals.
101
+
102
+ """
103
+ return self._decimals
104
+
105
+ @property
106
+ def asset_id(self) -> str:
107
+ """Get the asset ID.
108
+
109
+ Returns:
110
+ str: The asset ID.
111
+
112
+ """
113
+ return self._asset_id
114
+
115
+ @property
116
+ def contract_address(self) -> str:
117
+ """Get the contract address.
118
+
119
+ Returns:
120
+ str: The contract address.
121
+
122
+ """
123
+ return self._contract_address
124
+
125
+ @property
126
+ def network_id(self) -> str:
127
+ """Get the network ID.
128
+
129
+ Returns:
130
+ str: The network ID.
131
+
132
+ """
133
+ return self._network_id
134
+
135
+ def from_atomic_amount(self, atomic_amount: Decimal) -> Decimal:
136
+ """Convert an atomic amount to a whole amount.
137
+
138
+ Args:
139
+ atomic_amount (Decimal): The atomic amount.
140
+
141
+ Returns:
142
+ Decimal: The whole amount.
143
+
144
+ """
145
+ return Decimal(atomic_amount) / Decimal(10) ** (self.decimals)
146
+
147
+ def to_atomic_amount(self, whole_amount: Decimal) -> Decimal:
148
+ """Convert a whole amount to an atomic amount.
149
+
150
+ Args:
151
+ whole_amount (Decimal): The whole amount.
152
+
153
+ Returns:
154
+ Decimal: The atomic amount.
155
+
156
+ """
157
+ return whole_amount * Decimal(10) ** (self.decimals)
158
+
159
+ def __str__(self) -> str:
160
+ """Return a string representation of the Asset."""
161
+ return f"Asset: (asset_id: {self.asset_id}, network_id: {self.network_id}, contract_address: {self.contract_address}, decimals: {self.decimals})"
162
+
163
+ def __repr__(self) -> str:
164
+ """Return a string representation of the Asset."""
165
+ return str(self)
cdp/balance.py ADDED
@@ -0,0 +1,79 @@
1
+ from decimal import Decimal
2
+
3
+ from cdp.asset import Asset
4
+ from cdp.client.models.balance import Balance as BalanceModel
5
+
6
+
7
+ class Balance:
8
+ """A class representing a balance."""
9
+
10
+ def __init__(self, amount: Decimal, asset: Asset, asset_id: str | None = None):
11
+ """Initialize the Balance class.
12
+
13
+ Args:
14
+ amount (Decimal): The amount.
15
+ asset (Asset): The asset.
16
+ asset_id (Optional[str]): The asset ID.
17
+
18
+ """
19
+ self._amount = amount
20
+ self._asset = asset
21
+ self._asset_id = asset_id if asset_id is not None else asset.asset_id
22
+
23
+ @staticmethod
24
+ def from_model(model: BalanceModel, asset_id: str | None = None) -> "Balance":
25
+ """Create a Balance instance from a model.
26
+
27
+ Args:
28
+ model (BalanceModel): The model representing the balance.
29
+ asset_id (Optional[str]): The asset ID.
30
+
31
+ Returns:
32
+ Balance: The Balance instance.
33
+
34
+ """
35
+ asset = Asset.from_model(model.asset, asset_id=asset_id)
36
+
37
+ return Balance(
38
+ amount=asset.from_atomic_amount(model.amount),
39
+ asset=asset,
40
+ asset_id=asset_id,
41
+ )
42
+
43
+ @property
44
+ def amount(self) -> Decimal:
45
+ """Get the amount.
46
+
47
+ Returns:
48
+ Decimal: The amount.
49
+
50
+ """
51
+ return self._amount
52
+
53
+ @property
54
+ def asset(self) -> Asset:
55
+ """Get the asset.
56
+
57
+ Returns:
58
+ Asset: The asset.
59
+
60
+ """
61
+ return self._asset
62
+
63
+ @property
64
+ def asset_id(self) -> str:
65
+ """Get the asset ID.
66
+
67
+ Returns:
68
+ str: The asset ID.
69
+
70
+ """
71
+ return self._asset_id
72
+
73
+ def __str__(self) -> str:
74
+ """Return a string representation of the Balance."""
75
+ return f"Balance: (amount: {self.amount}, asset: {self.asset})"
76
+
77
+ def __repr__(self) -> str:
78
+ """Return a string representation of the Balance."""
79
+ return str(self)
cdp/balance_map.py ADDED
@@ -0,0 +1,75 @@
1
+ import json
2
+ from decimal import Decimal
3
+
4
+ from cdp.balance import Balance
5
+ from cdp.client.models.balance import Balance as BalanceModel
6
+
7
+
8
+ class BalanceMap(dict[str, Decimal]):
9
+ """A class representing asset balances.
10
+
11
+ This class extends the built-in dict class, where keys are asset IDs (str)
12
+ and values are balance amounts (Decimal).
13
+ """
14
+
15
+ @classmethod
16
+ def from_models(cls, models: list[BalanceModel]) -> "BalanceMap":
17
+ """Create a BalanceMap instance from a list of BalanceModel objects.
18
+
19
+ Args:
20
+ models (List[BalanceModel]): A list of BalanceModel objects.
21
+
22
+ Returns:
23
+ BalanceMap: A new BalanceMap instance populated with the given models.
24
+
25
+ """
26
+ balance_map = cls()
27
+
28
+ for model in models:
29
+ balance = Balance.from_model(model)
30
+ balance_map.add(balance)
31
+
32
+ return balance_map
33
+
34
+ def add(self, balance: Balance) -> None:
35
+ """Add a Balance object to the BalanceMap.
36
+
37
+ Args:
38
+ balance (Balance): The Balance object to add.
39
+
40
+ Raises:
41
+ ValueError: If the provided balance is not a Balance instance.
42
+
43
+ """
44
+ if not isinstance(balance, Balance):
45
+ raise ValueError("balance must be a Balance instance")
46
+
47
+ self[balance.asset_id] = balance.amount
48
+
49
+ def __str__(self) -> str:
50
+ """Return a JSON string representation of the BalanceMap.
51
+
52
+ Returns:
53
+ str: A JSON string with asset IDs as keys and formatted balance amounts as values.
54
+
55
+ """
56
+ result: dict[str, str] = {}
57
+
58
+ for asset_id, amount in self.items():
59
+ amount_str = format(amount, "f")
60
+
61
+ if amount == amount.to_integral():
62
+ amount_str = str(int(amount))
63
+
64
+ result[asset_id] = amount_str
65
+
66
+ return json.dumps(result, separators=(",", ":"))
67
+
68
+ def __repr__(self) -> str:
69
+ """Return a string representation of the BalanceMap.
70
+
71
+ Returns:
72
+ str: The string representation of the BalanceMap.
73
+
74
+ """
75
+ return str(self)