diff --git a/app/models/output.py b/app/models/output.py index 53c6a29..cb19dc4 100644 --- a/app/models/output.py +++ b/app/models/output.py @@ -3,6 +3,7 @@ from sqlalchemy.orm import Mapped from sqlalchemy import Numeric from sqlalchemy import String +from decimal import Decimal from .base import Base from typing import Any @@ -16,7 +17,7 @@ class Output(Base): blockhash: Mapped[str] = mapped_column(String(64), index=True) address: Mapped[str] = mapped_column(String(70), index=True) txid: Mapped[str] = mapped_column(String(64), index=True) - amount: Mapped[Numeric] = mapped_column(Numeric(28, 8)) + amount: Mapped[Decimal] = mapped_column(Numeric(28, 8)) timelock: Mapped[int] type: Mapped[str] = mapped_column(String(64), index=True) script: Mapped[str] diff --git a/tests/address/test_list_address_utxo.py b/tests/address/test_list_address_utxo.py new file mode 100644 index 0000000..50f9e69 --- /dev/null +++ b/tests/address/test_list_address_utxo.py @@ -0,0 +1,51 @@ +from sqlalchemy.ext.asyncio import AsyncSession +from async_asgi_testclient import TestClient +from tests.client_requests import addresses +from app.models.output import Output +from app.utils import to_satoshi +from tests import helpers +import secrets + + +async def test_default(client: TestClient, address_utxo: Output, session: AsyncSession): + extra_amount = 100 + + utxo1 = await helpers.create_output( + session, + address_utxo.currency, + address=address_utxo.address, + spent=False, + shortcut=secrets.token_hex(16), + amount=123, + ) + + required_amount = address_utxo.amount + utxo1.amount + extra_amount + + response = await addresses.get_address_utxo( + client, address_utxo.address, float(required_amount), "MBC" + ) + print(response.json()) + assert response.status_code == 200 + + assert response.json()["pagination"] == {"total": 2, "pages": 1, "page": 1} + + for txo in response.json()["list"]: + assert txo["timelock"] in (address_utxo.timelock, utxo1.timelock) + assert txo["amount"] in ( + to_satoshi(float(address_utxo.amount)), + to_satoshi(float(utxo1.amount)), + ) + assert txo["currency"] in (address_utxo.currency, utxo1.currency) + assert txo["index"] in (address_utxo.index, utxo1.index) + assert txo["type"] in (address_utxo.type, utxo1.type) + assert txo["txid"] in (address_utxo.txid, utxo1.txid) + assert txo["spent"] is False + + +async def test_none(client, address): + response = await addresses.get_address_utxo(client, address.address, 1, "MBC") + print(response.json()) + assert response.status_code == 200 + + assert response.json()["pagination"] == {"total": 0, "pages": 0, "page": 1} + assert response.json()["list"] == [] diff --git a/tests/client_requests/addresses.py b/tests/client_requests/addresses.py index 8f89b11..168daad 100644 --- a/tests/client_requests/addresses.py +++ b/tests/client_requests/addresses.py @@ -11,6 +11,16 @@ async def get_unspent_address_outputs( ) +async def get_address_utxo( + client: TestClient, address: str, amount: float, currency: str, page: int = 1 +): + """Do not confuse get_unspent_address_outputs with this function (this may sound similar, but its not the same)""" + return await client.get( + f"/address/{address}/utxo/{currency}", + query_string={"amount": amount, "page": page}, + ) + + async def get_address_transactions( client: TestClient, address: str, page: int = 1 ) -> Response: @@ -22,6 +32,4 @@ async def get_address_transactions( async def get_address_balances( client: TestClient, address: str, page: int = 1 ) -> Response: - return await client.get( - f"/address/{address}/balances", query_string={"page": page} - ) + return await client.get(f"/address/{address}/balances", query_string={"page": page})