diff --git a/src/fds/contracts/Multibox.py b/src/fds/contracts/Multibox.py
new file mode 100644
index 0000000..0fe2b20
--- /dev/null
+++ b/src/fds/contracts/Multibox.py
@@ -0,0 +1,28 @@
+"""
+Copyright 2023 The FairDataSociety Authors
+This file is part of the FairDataSociety library.
+
+The FairDataSociety library is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+The FairDataSociety library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the FairDataSociety library. If not, see .
+
+handles Multibox contract
+"""
+
+from typing import Tuple, Union
+
+from ape import convert, networks, project
+from ape.api.accounts import AccountAPI
+from ape.api.transactions import ReceiptAPI
+from ape.types import AddressType
+
+from fds.utils.Exceptions import AccountNotSetUp
diff --git a/src/fds/contracts/PublicResolver.py b/src/fds/contracts/PublicResolver.py
new file mode 100644
index 0000000..c06f54f
--- /dev/null
+++ b/src/fds/contracts/PublicResolver.py
@@ -0,0 +1,142 @@
+"""
+Copyright 2023 The FairDataSociety Authors
+This file is part of the FairDataSociety library.
+
+The FairDataSociety library is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+The FairDataSociety library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the FairDataSociety library. If not, see .
+
+handles PublicResolver contract
+"""
+from typing import Tuple, Union
+
+from ape import convert, networks, project
+from ape.api.accounts import AccountAPI
+from ape.api.transactions import ReceiptAPI
+from ape.types import AddressType
+
+from fds.utils.Exceptions import AccountNotSetUp
+
+
+class PublicResolverClass:
+ def __init__(self, account: AccountAPI, contract_address: Union[AddressType, None] = None):
+ self.account = account
+ self.contract_address = contract_address
+ self.contract = None
+ self.web3 = networks.provider._web3
+
+ if contract_address:
+ self.contract = project.PublicResolver.at(self.contract_address)
+
+ def setAll(
+ self,
+ node: int,
+ address: AddressType,
+ content: str,
+ multihash: str,
+ x: int,
+ y: int,
+ name: str,
+ ) -> ReceiptAPI:
+ """
+ * Sets all required params in one attempt
+ * May only be called by the owner of that node in the ENS registry.
+ * @param node The node to update.
+ * @param addr The address to set.
+ * @param content The content hash to set
+ * @param multihash The multihash to set
+ * @param x the X coordinate of the curve point for the public key.
+ * @param y the Y coordinate of the curve point for the public key.
+ * @param name The name to set.
+ """
+
+ """
+ If x = b'abc' then f"{x}" or "{}".format(x) produces "b'abc'", not "abc".
+ If this is desired behavior, use f"{x!r}" or "{!r}".format(x).
+ Otherwise, decode the bytes
+ """
+ self.node = f"0x{node.to_bytes(32, byteorder='big').hex()}"
+ self.address = address
+ self.content = content.encode("utf-8")
+ self.multihash = multihash.encode("utf-8")
+ self.x = x.to_bytes(32, byteorder="big")
+ self.y = y.to_bytes(32, byteorder="big")
+ self.name = name
+
+ return self.contract.setAll( # type: ignore
+ self.node,
+ self.address,
+ self.content,
+ self.multihash,
+ self.x,
+ self.y,
+ self.name,
+ sender=self.account,
+ )
+
+ def getAll(self, node: int) -> Tuple:
+ self.node = f"0x{node.to_bytes(32, byteorder='big').hex()}"
+
+ return self.contract.getAll(self.node) # type: ignore
+
+ def setPublicKey(self, node: int, x: int, y: int) -> ReceiptAPI:
+ """
+ * Sets the SECP256k1 public key associated with an ENS node.
+ * @param node The ENS node to query
+ * @param x the X coordinate of the curve point for the public key.
+ * @param y the Y coordinate of the curve point for the public key.
+ """
+ if not self.account:
+ raise AccountNotSetUp("Set up user account first")
+
+ self.node = f"0x{node.to_bytes(32, byteorder='big').hex()}"
+ self.x = x.to_bytes(32, byteorder="big")
+ self.y = y.to_bytes(32, byteorder="big")
+
+ return self.contract.setPubkey(self.node, self.x, self.y, sender=self.account) # type: ignore # noqa: 501
+
+ def getPublicKey(self, node: int) -> Tuple[int, int]:
+ """
+ * Returns the SECP256k1 public key associated with an ENS node.
+ * Defined in EIP 619.
+ * @param node The ENS node to query
+ * @return x, y the X and Y coordinates of the curve point for the public key.
+ """
+
+ self.node = f"0x{node.to_bytes(32, byteorder='big').hex()}"
+
+ return self.contract.pubkey(self.node) # type: ignore
+
+ def setMultiHash(self, node: int, _hash: str) -> ReceiptAPI:
+ """
+ * Sets the multihash associated with an ENS node.
+ * May only be called by the owner of that node in the ENS registry.
+ * @param node The node to update.
+ * @param hash The multihash to set.
+ """
+ if not self.account:
+ raise AccountNotSetUp("Set up user account first")
+
+ self.node = f"0x{node.to_bytes(32, byteorder='big').hex()}"
+ self.hash = _hash.encode("utf-8")
+
+ return self.contract.setMultihash(self.node, self.hash, sender=self.account) # type: ignore
+
+ def getMultiHash(self, node: int) -> str:
+ """
+ * Returns the multihash associated with an ENS node.
+ * @param node The ENS node to query.
+ * @return The associated multihash.
+ """
+ self.node = f"0x{node.to_bytes(32, byteorder='big').hex()}"
+
+ return convert(self.contract.multihash(self.node), str) # type: ignore
diff --git a/src/fds/contracts/SubdomainRegistrar.py b/src/fds/contracts/SubdomainRegistrar.py
new file mode 100644
index 0000000..e4e6693
--- /dev/null
+++ b/src/fds/contracts/SubdomainRegistrar.py
@@ -0,0 +1,60 @@
+"""
+Copyright 2023 The FairDataSociety Authors
+This file is part of the FairDataSociety library.
+
+The FairDataSociety library is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+The FairDataSociety library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the FairDataSociety library. If not, see .
+
+handles SubdomainRegistrar contract
+"""
+from typing import Union
+
+from ape import networks, project
+from ape.api.accounts import AccountAPI
+from ape.api.transactions import ReceiptAPI
+from ape.types import AddressType
+
+
+class SubdomainRegistrarContractClass:
+ def __init__(self, account: AccountAPI, contract_address: Union[AddressType, None] = None):
+ self.account = account
+ self.contract_address = contract_address
+ self.contract = None
+ self.web3 = networks.provider._web3
+
+ if contract_address:
+ self.contract = project.SubdomainRegistrar.at(self.contract_address)
+
+ def getRootNode(self) -> str:
+ return self.contract.rootNode() # type: ignore
+
+ def register(self, label: int, owner_address: AddressType) -> ReceiptAPI:
+ """
+ Register a name that's not currently registered
+ @param label The hash of the label to register.
+ @param owner The address of the new owner.
+ """
+
+ self.label = label.to_bytes(32, byteorder="big")
+ self.owner_address = owner_address
+ self.label = f"0x{self.label.hex()}" # type: ignore
+
+ return self.contract.register(self.label, self.owner_address, sender=self.account) # type: ignore # noqa: 501
+
+ def getExpiryTime(self, label: int):
+ self.label = label.to_bytes(32, byteorder="big")
+ self.label = f"0x{self.label.hex()}" # type: ignore
+
+ expiryTime = self.contract.expiryTimes(self.label) # type: ignore
+
+ return expiryTime
diff --git a/src/fds/contracts/multibox.py b/src/fds/contracts/multibox.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/fds/contracts/public_resolver.py b/src/fds/contracts/public_resolver.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/fds/contracts/subdomain_registrar.py b/src/fds/contracts/subdomain_registrar.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/fds/tests/conftest.py b/src/fds/tests/conftest.py
index 3821973..0a5ccd1 100644
--- a/src/fds/tests/conftest.py
+++ b/src/fds/tests/conftest.py
@@ -235,15 +235,23 @@ def fdsContractDeploy(owner):
@pytest.fixture
def ensContract(owner):
- contract = project.ENSRegistry.deploy(sender=owner)
-
- return contract
+ return project.ENSRegistry.deploy(sender=owner)
@pytest.fixture
def ENS(owner, ensContract):
- contract = ensContract
+ return EnsRegistry(owner, ensContract.address)
+
+
+@pytest.fixture
+def subDomainRegistrarContract(owner, ensContract):
+ node = 1
+ node = node.to_bytes(32, byteorder="big")
+ contract = project.SubdomainRegistrar.deploy(ensContract.address, node, sender=owner)
+
+ return contract
- ENS = EnsRegistry(owner, contract.address)
- return ENS
+@pytest.fixture
+def publicResolverContract(owner, ensContract):
+ return project.PublicResolver.deploy(ensContract.address, sender=owner)
diff --git a/src/fds/tests/unit_tests/test_ensregistry.py b/src/fds/tests/unit_tests/test_ensregistry.py
index cebd686..60b206f 100644
--- a/src/fds/tests/unit_tests/test_ensregistry.py
+++ b/src/fds/tests/unit_tests/test_ensregistry.py
@@ -42,7 +42,7 @@ def test_set_n_get_ttl(ENS):
assert ENS.getTTL(0) == 420
-def test_fail_setting_ttl(owner, receiver, ensContract):
+def test_fail_setting_ttl(owner, ensContract):
contract = ensContract
ENS = EnsRegistry(owner, contract.address)
diff --git a/src/fds/tests/unit_tests/test_public_resolver.py b/src/fds/tests/unit_tests/test_public_resolver.py
new file mode 100644
index 0000000..86b9904
--- /dev/null
+++ b/src/fds/tests/unit_tests/test_public_resolver.py
@@ -0,0 +1,54 @@
+import pytest
+from ape import convert
+from ape.exceptions import ContractLogicError
+
+from fds.contracts.PublicResolver import PublicResolverClass
+
+
+def test_set_all(owner, sender, publicResolverContract, ENS):
+ assert ENS.owner(0) == owner.address
+
+ pubResClass = PublicResolverClass(owner, publicResolverContract.address)
+
+ pubResClass.setAll(0, sender.address, "hahaha", "eeehahaha", 16, 17, "jadu")
+
+ addr, content, multihash, x, y, name = pubResClass.getAll(0)
+
+ assert addr == sender.address
+ assert content.decode().replace("\x00", "") == "hahaha"
+ assert multihash.decode().replace("\x00", "") == "eeehahaha"
+ assert convert(x, int) == 16
+ assert convert(y, int) == 17
+ assert name.replace("\x00", "") == "jadu"
+
+
+def test_set_publickey(owner, publicResolverContract):
+ pubResClass = PublicResolverClass(owner, publicResolverContract.address)
+ node = 0
+ pubResClass.setPublicKey(node, 22, 34)
+
+ x, y = pubResClass.getPublicKey(node)
+
+ assert convert(x, int) == 22
+ assert convert(y, int) == 34
+
+
+# TODO: fixt this test
+def test_multihash(owner, publicResolverContract):
+ pubResClass = PublicResolverClass(owner, publicResolverContract.address)
+ node = 0
+ _hash = "fairDataProtocl"
+ pubResClass.setMultiHash(node, _hash)
+
+ returned_hash = pubResClass.getMultiHash(node)
+
+ assert returned_hash == _hash
+
+
+def test_fail_set_publickey(owner, publicResolverContract):
+ pubResClass = PublicResolverClass(owner, publicResolverContract.address)
+ node = 1
+
+ with pytest.raises(ContractLogicError):
+ # * trying to access other node
+ pubResClass.setPublicKey(node, 22, 34)
diff --git a/src/fds/tests/unit_tests/test_subdomain_register.py b/src/fds/tests/unit_tests/test_subdomain_register.py
new file mode 100644
index 0000000..a0dd782
--- /dev/null
+++ b/src/fds/tests/unit_tests/test_subdomain_register.py
@@ -0,0 +1,20 @@
+import pytest
+from ape.exceptions import ContractLogicError
+
+from fds.contracts.SubdomainRegistrar import SubdomainRegistrarContractClass
+
+
+def test_load_ens_contract(owner, subDomainRegistrarContract):
+ contract = subDomainRegistrarContract
+ src = SubdomainRegistrarContractClass(owner, contract.address)
+ node = 1
+ node = node.to_bytes(32, byteorder="big")
+ assert src.getRootNode() == node
+
+
+def test_register(owner, ensContract):
+ src = SubdomainRegistrarContractClass(owner, ensContract.address)
+
+ # ENS.setOwner(0, owner.address)
+ with pytest.raises(ContractLogicError):
+ src.register(0, owner.address)
diff --git a/src/fds/utils/Exceptions.py b/src/fds/utils/Exceptions.py
index 5b5f648..cb79ada 100644
--- a/src/fds/utils/Exceptions.py
+++ b/src/fds/utils/Exceptions.py
@@ -12,3 +12,7 @@ class ContractNotFoundException(Exception):
class InaccessibleGatewayException(Exception):
pass
+
+
+class AccountNotSetUp(Exception):
+ pass