Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions blockapi/test/v2/api/data/unisat/collection_stats_full_url.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"code": 0,
"msg": "ok",
"data": {
"collectionId": "rune-mania-miner",
"name": "Rune Mania Miner",
"desc": "Rune Mania: Utilize your RMM to mine Runes using:⛏️ Mining Boosts🧱 Block Boosts🧪 Mana Boosts🗿 Stone Boosts ✨ Rune Boosts",
"icon": "https://creator-hub-prod.s3.us-east-2.amazonaws.com/ord-rmm_pfp_1708461604099.png",
"btcValue": 0,
"btcValuePercent": 0,
"floorPrice": 80000,
"listed": 9,
"total": 3800,
"supply": null,
"attrs": [],
"twitter": "https://twitter.com/RuneManiaMiner",
"discord": null,
"website": "https://www.ord.io/61549984",
"pricePercent": 0,
"verification": false
}
}
94 changes: 56 additions & 38 deletions blockapi/test/v2/api/nft/test_unisat.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,36 +24,62 @@
test_nft_type = BtcNftType.COLLECTION


def test_fetch_collection(requests_mock, unisat_client, collection_stats):
def test_fetch_collection_icon_code(requests_mock, unisat_client, collection_stats):
"""
UniSat sometimes sends only the icon *code* ― no URL.
We expect `parse_collection` to prepend the static CDN prefix automatically.
"""
requests_mock.post(
f"{unisat_client.api_options.base_url}v3/market/collection/auction/collection_statistic",
f"{unisat_client.api_options.base_url}"
"v3/market/collection/auction/collection_statistic",
text=collection_stats,
)

test_collection = "pixel-pepes"
fetch_result = unisat_client.fetch_collection(test_collection)
assert not fetch_result.errors, f"Fetch errors: {fetch_result.errors}"
fetch_result = unisat_client.fetch_collection("pixel-pepes")
assert not fetch_result.errors

parsed = unisat_client.parse_collection(fetch_result)
assert not parsed.errors and len(parsed.data) == 1

col: NftCollection = parsed.data[0]
assert col.ident == "pixel-pepes"
assert col.name == "Pixel Pepes"
assert (
col.image == "https://static.unisat.io/content/"
"47c1d21c508f6d49dfde64d958f14acd041244e1bb616f9b78114b8d9dc7b945i0"
)
assert str(col.total_stats.floor_price) == "0.0099"
assert str(col.total_stats.volume) == "0.399"


parse_result = unisat_client.parse_collection(fetch_result)
assert not parse_result.errors, f"Parse errors: {parse_result.errors}"
assert len(parse_result.data) == 1
def test_fetch_collection_icon_full_url(
requests_mock, unisat_client, collection_stats_full_url
):
"""
UniSat may also deliver a *fully-qualified* icon URL.
In that case we should **not** touch the value.
"""
requests_mock.post(
f"{unisat_client.api_options.base_url}"
"v3/market/collection/auction/collection_statistic",
text=collection_stats_full_url,
)

fetch_result = unisat_client.fetch_collection("rune-mania-miner")
assert not fetch_result.errors

collection = parse_result.data[0]
assert isinstance(collection, NftCollection)
assert collection.ident == "pixel-pepes"
assert collection.name == "Pixel Pepes"
parsed = unisat_client.parse_collection(fetch_result)
assert not parsed.errors and len(parsed.data) == 1

col: NftCollection = parsed.data[0]
assert col.ident == "rune-mania-miner"
assert col.name == "Rune Mania Miner"
assert (
collection.image
== "https://static.unisat.io/content/47c1d21c508f6d49dfde64d958f14acd041244e1bb616f9b78114b8d9dc7b945i0"
col.image == "https://creator-hub-prod.s3.us-east-2.amazonaws.com/"
"ord-rmm_pfp_1708461604099.png"
)
assert not collection.is_disabled
assert not collection.is_nsfw
assert collection.blockchain == Blockchain.BITCOIN
assert str(collection.total_stats.floor_price) == "0.0099"
assert str(collection.total_stats.owners_count) == "1563"
assert str(collection.total_stats.sales_count) == "20"
assert str(collection.total_stats.volume) == "0.399"
assert str(collection.total_stats.market_cap) == "15.4737"

assert str(col.total_stats.floor_price) == "0.0008"


def test_fetch_listings(requests_mock, unisat_client, listings_data):
Expand Down Expand Up @@ -153,21 +179,6 @@ def unisat_client(fake_sleep_provider):
return UnisatApi(api_key="test_key", sleep_provider=fake_sleep_provider)


@pytest.fixture
def inscription_data():
return read_file('data/unisat/inscription_data.json')


@pytest.fixture
def inscription_data_edge_cases():
return read_file('data/unisat/inscription_data_edge_cases.json')


@pytest.fixture
def collection_edge_cases():
return read_file('data/unisat/collection_edge_cases.json')


@pytest.fixture
def listings_data():
return read_file('data/unisat/listings.json')
Expand All @@ -180,4 +191,11 @@ def offers_data():

@pytest.fixture
def collection_stats():
return read_file('data/unisat/collection_stats.json')
"""Pixel Pepes – icon **code** only."""
return read_file("data/unisat/collection_stats.json")


@pytest.fixture
def collection_stats_full_url():
"""Rune Mania Miner – icon is a full URL."""
return read_file("data/unisat/collection_stats_full_url.json")
17 changes: 9 additions & 8 deletions blockapi/v2/api/nft/unisat.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,23 +293,24 @@ def parse_collection(self, fetch_result: FetchResult) -> ParseResult:
# Format the icon URL
icon = stats.get("icon")
icon_url = None

if icon:
icon_url = f"https://static.unisat.io/content/{icon}"
if icon.startswith(("http://", "https://")):
icon_url = icon
else:
icon_url = f"https://static.unisat.io/content/{icon.lstrip('/')}"

floor_price = raw_to_decimals(stats.get("floorPrice", 0), self.coin.decimals)

volume = raw_to_decimals(stats.get("btcValue", 0), self.coin.decimals)

total_nfts = stats.get("total", 0)
market_cap = floor_price * total_nfts if total_nfts else 0

total_stats = NftCollectionTotalStats.from_api(
volume=str(volume),
sales_count=str(stats.get("listed", 0)),
owners_count=str(total_nfts),
market_cap=str(market_cap),
sales_count=None,
owners_count=None,
market_cap=None,
floor_price=str(floor_price),
average_price="0",
average_price=None,
coin=self.coin,
)

Expand Down