Skip to content

Commit ffafe2c

Browse files
committed
add get_token_price and get_nft_holders
1 parent 661d269 commit ffafe2c

File tree

5 files changed

+104
-2
lines changed

5 files changed

+104
-2
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,11 @@ logs = ankr_w3.query.get_logs(
8585

8686
- [`nft.get_nfts`](#get_nfts)
8787
- [`nft.get_nft_metadata`](#get_nft_metadata)
88+
- `nft.get_nft_holders`
8889
- [`token.get_token_holders`](#get_token_holders)
8990
- [`token.get_token_holders_count_history`](#get_token_holders_count_history)
9091
- [`token.get_token_holders_count`](#get_token_holders_count)
92+
- `token.get_token_price`
9193
- [`token.get_account_balance`](#get_account_balance)
9294
- [`query.get_logs`](#get_logs)
9395
- [`query.get_blocks`](#get_blocks)

ankr/advanced_apis.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,24 @@ def get_token_holders_count(
164164
raise APIError("no token holders count found")
165165
return reply.holder_count_history[0]
166166

167+
def get_token_price(
168+
self,
169+
blockchain: types.BlockchainName,
170+
contract_address: str,
171+
**kwargs: Any,
172+
) -> str:
173+
reply = self.provider.call_method(
174+
rpc="ankr_getTokenPrice",
175+
request=types.GetTokenPriceRequest(
176+
blockchain=blockchain,
177+
contract_address=contract_address,
178+
**kwargs,
179+
),
180+
reply_type=types.GetTokenPriceReply,
181+
)
182+
183+
return reply.usd_price
184+
167185
def get_account_balance(
168186
self,
169187
wallet_address: str,
@@ -228,6 +246,26 @@ def get_nft_metadata(
228246
types.GetNFTMetadataReply,
229247
)
230248

249+
def get_nft_holders(
250+
self,
251+
blockchain: types.BlockchainName,
252+
contract_address: str,
253+
limit: Optional[int] = None,
254+
**kwargs: Any,
255+
) -> Iterable[types.Address]:
256+
return self.provider.call_method_paginated(
257+
"ankr_getNFTHolders",
258+
types.GetNFTHoldersRequest(
259+
blockchain=blockchain,
260+
contract_address=contract_address,
261+
**kwargs,
262+
),
263+
types.GetNFTHoldersReply,
264+
iterable_name="holders",
265+
iterable_type=types.Address,
266+
limit=limit,
267+
)
268+
231269

232270
class AnkrAdvancedAPI(AnkrQueryAPI, AnkrTokenAPI, AnkrNFTAPI):
233271
...

ankr/providers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from ankr.exceptions import APIError
1212

1313
TRequest = TypeVar("TRequest", bound=types.RPCModel)
14-
TReply = TypeVar("TReply", bound=types.RPCModel)
14+
TReply = TypeVar("TReply")
1515
TRequestPaginated = TypeVar("TRequestPaginated", bound=types.RPCRequestPaginated)
1616
TReplyPaginated = TypeVar("TReplyPaginated", bound=types.RPCReplyPaginated)
1717

ankr/types.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class BlockNumberName(str, enum.Enum):
3232
BlockchainName = Union[Blockchain, str]
3333
BlockchainNames = Union[BlockchainName, List[BlockchainName]]
3434
BlockNumber = Union[int, str, BlockNumberName]
35+
Address = str
3536
AddressOrAddresses = Union[str, List[str]]
3637
Topics = Union[str, List[Union[str, List[str]]]]
3738

@@ -117,6 +118,18 @@ class GetNFTMetadataReply(RPCModel):
117118
attributes: Optional[NftAttributes] = None
118119

119120

121+
class GetNFTHoldersRequest(RPCRequestPaginated):
122+
blockchain: BlockchainName
123+
contract_address: Address
124+
page_token: Optional[str] = None
125+
page_size: Optional[int] = None
126+
127+
128+
class GetNFTHoldersReply(RPCReplyPaginated):
129+
holders: List[Address]
130+
next_page_token: Optional[str] = None
131+
132+
120133
class Balance(RPCModel):
121134
blockchain: str
122135
token_name: str
@@ -174,6 +187,17 @@ class GetTokenHoldersCountRequest(RPCRequestPaginated):
174187
page_size: Optional[int] = None
175188

176189

190+
class GetTokenPriceRequest(RPCModel):
191+
blockchain: BlockchainName
192+
contract_address: str
193+
194+
195+
class GetTokenPriceReply(RPCModel):
196+
usd_price: str
197+
blockchain: BlockchainName
198+
contract_address: str
199+
200+
177201
class DailyHolderCount(RPCModel):
178202
holder_count: int
179203
total_amount: str
@@ -315,7 +339,7 @@ class Config:
315339
contract_address: Optional[str]
316340
cumulative_gas_used: str
317341
gas_used: str
318-
logs: List[Log]
342+
logs: Optional[List[Log]]
319343
logs_bloom: str
320344
transaction_hash: str
321345
hash: str

tests/test_client.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,21 @@ def test_get_nft_metadata() -> None:
9797
assert reply.attributes.name == "Overleveraged"
9898

9999

100+
@pytest.mark.webtest
101+
def test_get_nft_holders() -> None:
102+
client = AnkrAdvancedAPI()
103+
holders = list(
104+
client.get_nft_holders(
105+
blockchain="eth",
106+
contract_address="0x4100670ee2f8aef6c47a4ed13c7f246e621228ec",
107+
limit=10,
108+
)
109+
)
110+
111+
assert holders
112+
assert len(holders) == 10
113+
114+
100115
@pytest.mark.webtest
101116
def test_get_transactions() -> None:
102117
client = AnkrAdvancedAPI()
@@ -179,3 +194,26 @@ def test_get_account_balance() -> None:
179194

180195
assert assets
181196
assert len(assets) > 0
197+
198+
199+
@pytest.mark.webtest
200+
def test_get_token_price() -> None:
201+
client = AnkrAdvancedAPI()
202+
price = client.get_token_price(
203+
contract_address="0x8290333cef9e6d528dd5618fb97a76f268f3edd4",
204+
blockchain="eth",
205+
)
206+
207+
assert price
208+
assert float(price) > 0
209+
210+
211+
@pytest.mark.webtest
212+
def test_get_token_price__no_price() -> None:
213+
client = AnkrAdvancedAPI()
214+
price = client.get_token_price(
215+
contract_address="0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
216+
blockchain="eth",
217+
)
218+
219+
assert price == "0"

0 commit comments

Comments
 (0)