Skip to content

Commit

Permalink
Mint module (#122)
Browse files Browse the repository at this point in the history
* Add Mint module

 * Create MintRestClient
 * Create Mint tests

* fix after check

Signed-off-by: David Pierret <[email protected]>

* Managment of the wrong value encoding

Some endpoints reply with strings when base64 encoded
values are expected.
The tests check that all the values are correct

Signed-off-by: David Pierret <[email protected]>

* fix lint issues

Signed-off-by: David Pierret <[email protected]>

* chores: fix docstrings

* chores: fix more docstrings

* pylint/mypy/linting fixes

Co-authored-by: David Pierret <[email protected]>
Co-authored-by: Flavien Binet <[email protected]>
Co-authored-by: Galadrin <[email protected]>
  • Loading branch information
4 people authored Mar 29, 2022
1 parent b43c96b commit d816fcc
Show file tree
Hide file tree
Showing 9 changed files with 350 additions and 1 deletion.
21 changes: 21 additions & 0 deletions cosmpy/mint/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
#
# Copyright 2018-2021 Fetch.AI Limited
# Modifications copyright (C) 2022 Cros-Nest
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ------------------------------------------------------------------------------

"""This package contains the Mint module."""
54 changes: 54 additions & 0 deletions cosmpy/mint/interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
#
# Copyright 2018-2021 Fetch.AI Limited
# Modifications copyright (C) 2022 Cros-Nest
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ------------------------------------------------------------------------------

"""Interface for the Mint functionality of CosmosSDK."""

from abc import ABC, abstractmethod

from cosmpy.protos.cosmos.mint.v1beta1.query_pb2 import (
QueryAnnualProvisionsResponse,
QueryInflationResponse,
QueryParamsResponse,
)


class Mint(ABC):
"""Mint abstract class."""

@abstractmethod
def AnnualProvisions(self) -> QueryAnnualProvisionsResponse:
"""
AnnualProvisions current minting annual provisions value.
:return: a QueryAnnualProvisionsResponse instance
"""

@abstractmethod
def Inflation(self) -> QueryInflationResponse:
"""
Inflation returns the current minting inflation value.
:return: a QueryInflationResponse instance
"""

@abstractmethod
def Params(self) -> QueryParamsResponse:
"""
Params returns the total set of minting parameters.
:return: QueryParamsResponse
"""
102 changes: 102 additions & 0 deletions cosmpy/mint/rest_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
#
# Copyright 2018-2021 Fetch.AI Limited
# Modifications copyright (C) 2022 Cros-Nest
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ------------------------------------------------------------------------------

"""Implementation of Mint interface using REST."""
import base64
import json
from typing import Union

from google.protobuf.json_format import Parse

from cosmpy.common.rest_client import RestClient
from cosmpy.mint.interface import Mint
from cosmpy.protos.cosmos.mint.v1beta1.query_pb2 import (
QueryAnnualProvisionsResponse,
QueryInflationResponse,
QueryParamsResponse,
)


def isNumber(value: Union[str, bytes]) -> bool:
"""
Check is string ob bytes is number.
:param value: str, bytes
:return: bool
"""
try:
float(str(value))
return True
except ValueError:
return False


class MintRestClient(Mint):
"""Mint REST client."""

API_URL = "/cosmos/mint/v1beta1"

def __init__(self, rest_api: RestClient) -> None:
"""
Initialize.
:param rest_api: RestClient api
"""
self._rest_api = rest_api

def AnnualProvisions(self) -> QueryAnnualProvisionsResponse:
"""
AnnualProvisions current minting annual provisions value.
:return: a QueryAnnualProvisionsResponse instance
"""
json_response = self._rest_api.get(f"{self.API_URL}/annual_provisions")
# The QueryAnnualProvisionsResponse expect a base64 encoded value
# but the Rest endpoint return digits
j = json.loads(json_response)
if isNumber(j["annual_provisions"]):
j["annual_provisions"] = base64.b64encode(
j["annual_provisions"].encode()
).decode("utf8")
json_response = json.dumps(j).encode("utf-8")

return Parse(json_response, QueryAnnualProvisionsResponse())

def Inflation(self) -> QueryInflationResponse:
"""
Inflation returns the current minting inflation value.
:return: a QueryInflationResponse instance
"""
json_response = self._rest_api.get(f"{self.API_URL}/inflation")
# The QueryInflationResponse expect a base64 encoded value
# but the Rest endpoint return digits
j = json.loads(json_response)
if isNumber(j["inflation"]):
j["inflation"] = base64.b64encode(j["inflation"].encode()).decode("utf8")
json_response = json.dumps(j).encode("utf-8")

return Parse(json_response, QueryInflationResponse())

def Params(self) -> QueryParamsResponse:
"""
Params queries params of the Mint module.
:return: a QueryParamsResponse instance
"""
json_response = self._rest_api.get(f"{self.API_URL}/params")
return Parse(json_response, QueryParamsResponse())
3 changes: 2 additions & 1 deletion cosmpy/protos/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"""This package includes autogenerated implementation of protocol buffer schema files."""
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
#
# Copyright 2018-2021 Fetch.AI Limited
# Copyright 2018-2022 Fetch.AI Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down
20 changes: 20 additions & 0 deletions cosmpy/protos/cosmos/airdrop/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
#
# Copyright 2018-2022 Fetch.AI Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ------------------------------------------------------------------------------

"""This package contains module airdrop."""
File renamed without changes.
File renamed without changes.
21 changes: 21 additions & 0 deletions tests/unit/test_mint/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
#
# Copyright 2018-2021 Fetch.AI Limited
# Modifications copyright (C) 2022 Cros-Nest
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ------------------------------------------------------------------------------

"""This package contains tests for the Mint modules."""
130 changes: 130 additions & 0 deletions tests/unit/test_mint/test_rest_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
#
# Copyright 2018-2021 Fetch.AI Limited
# Modifications copyright (C) 2022 Cros-Nest
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ------------------------------------------------------------------------------

"""Tests for REST implementation of Mint."""
import base64
import json
import unittest

from google.protobuf.json_format import ParseDict

from cosmpy.mint.rest_client import MintRestClient
from cosmpy.protos.cosmos.mint.v1beta1.query_pb2 import (
QueryAnnualProvisionsResponse,
QueryInflationResponse,
QueryParamsResponse,
)
from tests.helpers import MockRestClient


class MintRestClientTestCase(unittest.TestCase):
"""Test case of Mint module."""

@staticmethod
def test_AnnualProvisionsBase64():
"""Test query annual provision for the positive result."""
content = {
"annual_provisions": "MTIzNA=="
} # use value "1234" in base64 encoded format

mock_client = MockRestClient(json.dumps(content))

expected_response = ParseDict(content, QueryAnnualProvisionsResponse())

mint = MintRestClient(mock_client)

assert mint.AnnualProvisions() == expected_response
assert expected_response.annual_provisions == b"1234"
assert mock_client.last_base_url == "/cosmos/mint/v1beta1/annual_provisions"

@staticmethod
def test_AnnualProvisionsInteger():
"""Test query annual provision for the positive result."""
content = {"annual_provisions": "1234"}

mock_client = MockRestClient(json.dumps(content))

expected_response = ParseDict(content, QueryAnnualProvisionsResponse())
# The AnnualProvisions object is expecting a base64 encoded value
expected_response.annual_provisions = base64.b64encode(
expected_response.annual_provisions
)

mint = MintRestClient(mock_client)
provision = mint.AnnualProvisions()
assert provision == expected_response
assert expected_response.annual_provisions == b"1234"
assert mock_client.last_base_url == "/cosmos/mint/v1beta1/annual_provisions"

@staticmethod
def test_InflationBase64():
"""Test query inflation for the positive result."""
content = {"inflation": "MC4wMTIzNDU="}

mock_client = MockRestClient(json.dumps(content))

expected_response = ParseDict(content, QueryInflationResponse())

mint = MintRestClient(mock_client)

assert mint.Inflation() == expected_response
assert mint.Inflation().inflation == b"0.012345"
assert mock_client.last_base_url == "/cosmos/mint/v1beta1/inflation"

@staticmethod
def test_InflationInteger():
"""Test query inflation for the positive result."""
content = {"inflation": "0.012345"}

mock_client = MockRestClient(json.dumps(content))

expected_response = ParseDict(content, QueryInflationResponse())
# The Inflation object is expecting a base64 encoded value
# FIXME: The create an issue by loosing the decimal dot and adding padding '=' # pylint: disable=W0511
expected_response.inflation = base64.b64encode(expected_response.inflation)

mint = MintRestClient(mock_client)

# This test is expected to fail because of the loss of the decimal dot.
# assert mint.Inflation() == expected_response
assert mint.Inflation().inflation == b"0.012345"
assert mock_client.last_base_url == "/cosmos/mint/v1beta1/inflation"

@staticmethod
def test_query_params():
"""Test query params for the positive result."""
content = {
"params": {
"mintDenom": "string",
"inflationRate": "0.12345",
"blocksPerYear": "1234",
}
}
mock_client = MockRestClient(json.dumps(content))

expected_response = ParseDict(content, QueryParamsResponse())

mint = MintRestClient(mock_client)

assert mint.Params().params.blocks_per_year == 1234
assert mint.Params().params.inflation_rate == "0.12345"
assert mint.Params().params.mint_denom == "string"
assert mint.Params() == expected_response
assert mock_client.last_base_url == "/cosmos/mint/v1beta1/params"

0 comments on commit d816fcc

Please sign in to comment.