diff --git a/sdk/py/apepay/__init__.py b/sdk/py/apepay/__init__.py index 09e8e21..4cd5aae 100644 --- a/sdk/py/apepay/__init__.py +++ b/sdk/py/apepay/__init__.py @@ -1,3 +1,4 @@ +from .factory import StreamFactory, releases from .manager import StreamManager from .streams import Stream from .validators import Validator @@ -8,6 +9,8 @@ __all__ = [ Stream.__name__, + StreamFactory.__name__, StreamManager.__name__, Validator.__name__, + "releases", ] diff --git a/sdk/py/apepay/exceptions.py b/sdk/py/apepay/exceptions.py index a87fb05..be7f0fe 100644 --- a/sdk/py/apepay/exceptions.py +++ b/sdk/py/apepay/exceptions.py @@ -9,6 +9,13 @@ class ApePayException(Exception): pass +class NoFactoryAvailable(ApePayException, RuntimeError): + def __init__(self): + super().__init__( + "No deployment of 'StreamFactory' on this chain, please use an explicit address." + ) + + class MissingCreationReceipt(ApePayException, NotImplementedError): def __init__(self): super().__init__("Missing creation transaction for stream. Functionality unavailabie.") diff --git a/sdk/py/apepay/factory.py b/sdk/py/apepay/factory.py new file mode 100644 index 0000000..05abe47 --- /dev/null +++ b/sdk/py/apepay/factory.py @@ -0,0 +1,58 @@ +from typing import Any + +from ape.contracts import ContractInstance +from ape.types import AddressType, BaseInterfaceModel +from pydantic import field_validator + +from .exceptions import NoFactoryAvailable +from .manager import StreamManager +from .package import MANIFEST + + +class StreamFactory(BaseInterfaceModel): + address: AddressType + + def __init__(self, address=None, /, *args, **kwargs): + if address is not None: + kwargs["address"] = address + + elif len(MANIFEST.StreamFactory.deployments) == 0: + raise NoFactoryAvailable() + + else: + kwargs["address"] = MANIFEST.StreamFactory.deployments[-1] + + super().__init__(*args, **kwargs) + + def __hash__(self) -> int: + return self.address.__hash__() + + @field_validator("address", mode="before") + def normalize_address(cls, value: Any) -> AddressType: + return cls.conversion_manager.convert(value, AddressType) + + @property + def contract(self) -> ContractInstance: + return MANIFEST.StreamFactory.at(self.address) + + def get_deployment(self, deployer: Any) -> StreamManager: + # TODO: Add product selection to the factory using `product=` kwarg (defaults to empty) + return StreamManager(self.contract.deployments(deployer)) + + +class Releases: + def __getitem__(self, release: int) -> StreamFactory: + if ( + len(MANIFEST.StreamFactory.deployments) < release + or len(MANIFEST.StreamFactory.deployments) == 0 + ): + raise IndexError("release index out of range") from NoFactoryAvailable() + + return StreamFactory(MANIFEST.StreamFactory.deployments[release]) + + @property + def latest(self) -> StreamFactory: + return StreamFactory() + + +releases = Releases()