From 2b1a69493c4f8c9a987756f400a64b3c3ab2d392 Mon Sep 17 00:00:00 2001
From: Doan Bui <bxdoan93@gmail.com>
Date: Thu, 15 Dec 2022 17:28:24 +0700
Subject: [PATCH] fix some typo and create utils (#4)

* fix some typo and create utils

* add constants

* add constants

* change import code style
---
 src/pynear/account.py                  | 51 +++++++++++++-------------
 src/pynear/constants.py                |  5 +++
 src/pynear/dapps/phone/async_client.py |  2 +-
 src/pynear/providers.py                |  6 ++-
 src/pynear/utils.py                    |  9 +++++
 5 files changed, 45 insertions(+), 28 deletions(-)
 create mode 100644 src/pynear/constants.py
 create mode 100644 src/pynear/utils.py

diff --git a/src/pynear/account.py b/src/pynear/account.py
index 3dad99c..43e5da8 100644
--- a/src/pynear/account.py
+++ b/src/pynear/account.py
@@ -1,5 +1,4 @@
 import asyncio
-import datetime
 import json
 from typing import List, Union
 
@@ -8,6 +7,8 @@
 from pyonear.crypto import InMemorySigner, ED25519SecretKey
 from pyonear.transaction import Action
 
+from pynear import utils
+from pynear import constants
 from pynear.dapps.ft.async_client import FT
 from pynear.dapps.phone.async_client import Phone
 from pynear.exceptions.exceptions import (
@@ -34,7 +35,6 @@
 from pynear.providers import JsonProvider
 from pynear import transactions
 
-DEFAULT_ATTACHED_GAS = 200000000000000
 
 
 _ERROR_TYPE_TO_EXCEPTION = {
@@ -70,7 +70,7 @@ class Account(object):
     chain_id: str = "mainnet"
 
     def __init__(
-        self, account_id, private_key, rpc_addr="https://rpc.mainnet.near.org"
+        self, account_id, private_key, rpc_addr=constants.RPC_MAINNET
     ):
         if isinstance(private_key, str):
             private_key = base58.b58decode(private_key.replace("ed25519:", ""))
@@ -93,15 +93,15 @@ async def startup(self):
 
     async def _update_last_block_hash(self):
         """
-        Update last block hash& If it's older than 100 block before, transaction will fail
+        Update last block hash& If it's older than 50 block before, transaction will fail
         :return: last block hash
         """
-        if self._latest_block_hash_ts + 50 > datetime.datetime.utcnow().timestamp():
+        if self._latest_block_hash_ts + 50 > utils.timestamp():
             return
         self._latest_block_hash = (await self._provider.get_status())["sync_info"][
             "latest_block_hash"
         ]
-        self._latest_block_hash_ts = datetime.datetime.utcnow().timestamp()
+        self._latest_block_hash_ts = utils.timestamp()
 
     async def _sign_and_submit_tx(
         self, receiver_id, actions: List[Action], nowait=False
@@ -119,7 +119,7 @@ async def _sign_and_submit_tx(
             await self._update_last_block_hash()
 
             block_hash = base58.b58decode(self._latest_block_hash.encode("utf8"))
-            serialzed_tx = transactions.sign_and_serialize_transaction(
+            serialized_tx = transactions.sign_and_serialize_transaction(
                 receiver_id,
                 access_key.nonce + 1,
                 actions,
@@ -127,9 +127,9 @@ async def _sign_and_submit_tx(
                 self._signer,
             )
             if nowait:
-                return await self._provider.send_tx(serialzed_tx)
+                return await self._provider.send_tx(serialized_tx)
 
-            result = await self._provider.send_tx_and_wait(serialzed_tx)
+            result = await self._provider.send_tx_and_wait(serialized_tx)
             if "Failure" in result["status"]:
                 error_type, args = list(
                     result["status"]["Failure"]["ActionError"]["kind"].items()
@@ -139,15 +139,15 @@ async def _sign_and_submit_tx(
         return TransactionResult(**result)
 
     @property
-    def account_id(self):
+    def account_id(self) -> AccountId:
         return self._account_id
 
     @property
-    def signer(self):
+    def signer(self) -> InMemorySigner:
         return self._signer
 
     @property
-    def provider(self):
+    def provider(self) -> JsonProvider:
         return self._provider
 
     async def get_access_key(self) -> AccountAccessKey:
@@ -171,15 +171,16 @@ async def get_access_key_list(self, account_id: str = None) -> List[PublicKey]:
             account_id = self._account_id
         resp = await self._provider.get_access_key_list(account_id)
         result = []
-        for key in resp["keys"]:
-            result.append(PublicKey.build(key))
+        if "keys" in resp and isinstance(resp["keys"], list):
+            for key in resp["keys"]:
+                result.append(PublicKey(**key))
         return result
 
-    async def fetch_state(self):
+    async def fetch_state(self) -> dict:
         """Fetch state for given account."""
         return await self._provider.get_account(self._account_id)
 
-    async def send_money(self, account_id: str, amount: int, nowait=False):
+    async def send_money(self, account_id: str, amount: int, nowait: bool = False) -> TransactionResult:
         """
         Send money to account_id
         :param account_id: receiver account id
@@ -196,17 +197,17 @@ async def function_call(
         contract_id: str,
         method_name: str,
         args: dict,
-        gas=DEFAULT_ATTACHED_GAS,
-        amount=0,
-        nowait=False,
+        gas: int = constants.DEFAULT_ATTACHED_GAS,
+        amount: int = 0,
+        nowait: bool = False,
     ):
         """
         Call function on smart contract
-        :param contract_id: smart contract adress
+        :param contract_id: smart contract address
         :param method_name: call method name
         :param args: json params for method
-        :param gas: amount of attachment gas
-        :param amount: amount of attachment NEAR
+        :param gas: amount of attachment gas. Default is 200000000000000
+        :param amount: amount of attachment NEAR, Default is 0
         :param nowait: if nowait is True, return transaction hash, else wait execution
         :return: transaction hash or TransactionResult
         """
@@ -225,7 +226,7 @@ async def create_account(
         nowait=False,
     ):
         """
-        Create new account in subdomian of current account. For example, if current account is "test.near",
+        Create new account in subdomain of current account. For example, if current account is "test.near",
         you can create "wwww.test.near"
         :param account_id: new account id
         :param public_key: add public key to new account
@@ -245,7 +246,7 @@ async def add_public_key(
         public_key: Union[str, bytes],
         receiver_id: str,
         method_names: List[str] = None,
-        allowance: int = 25000000000000000000000,
+        allowance: int = constants.ALLOWANCE,
         nowait=False,
     ):
         """
@@ -268,7 +269,7 @@ async def add_public_key(
 
     async def add_full_access_public_key(
         self, public_key: Union[str, bytes], nowait=False
-    ):
+    ) -> TransactionResult:
         """
         Add public key to account with full access
         :param public_key: public_key to add
diff --git a/src/pynear/constants.py b/src/pynear/constants.py
new file mode 100644
index 0000000..278bd30
--- /dev/null
+++ b/src/pynear/constants.py
@@ -0,0 +1,5 @@
+
+TIMEOUT_WAIT_RPC = 60
+DEFAULT_ATTACHED_GAS = 200000000000000
+ALLOWANCE = 25000000000000000000000
+RPC_MAINNET = "https://rpc.mainnet.near.org"
\ No newline at end of file
diff --git a/src/pynear/dapps/phone/async_client.py b/src/pynear/dapps/phone/async_client.py
index 34a17af..1ffe816 100644
--- a/src/pynear/dapps/phone/async_client.py
+++ b/src/pynear/dapps/phone/async_client.py
@@ -97,7 +97,7 @@ async def send_near_to_phone(
         self, phone: str, amount: float, comment: str = "", nowait: bool = False
     ):
         """
-        Send NEAR to phone number. Reciver will get sms with link to claim tokens.
+        Send NEAR to phone number. Receiver will get sms with link to claim tokens.
         :param phone: +X format phone number
         :param amount: number of NEAR which will be sent
         :param comment: any comment
diff --git a/src/pynear/providers.py b/src/pynear/providers.py
index 14930b4..1419cf8 100644
--- a/src/pynear/providers.py
+++ b/src/pynear/providers.py
@@ -3,7 +3,7 @@
 
 import aiohttp
 from aiohttp import ClientResponseError, ClientConnectorError
-
+from pynear import constants
 from pynear.exceptions.exceptions import RpcNotAvailableError
 from pynear.exceptions.provider import (
     UnknownBlockError,
@@ -21,6 +21,7 @@
     ERROR_CODE_TO_EXCEPTION,
 )
 
+
 _ERROR_CODE_TO_EXCEPTION = {
     "UNKNOWN_BLOCK": UnknownBlockError,
     "INVALID_ACCOUNT": InvalidAccount,
@@ -96,10 +97,11 @@ async def send_tx(self, signed_tx: str):
             "broadcast_tx_async", [signed_tx]
         )
 
-    async def send_tx_and_wait(self, signed_tx: str, timeout=60):
+    async def send_tx_and_wait(self, signed_tx: str, timeout: int = constants.TIMEOUT_WAIT_RPC):
         """
         Send a signed transaction to the network and wait for it to be included in a block.
         :param signed_tx: base64 encoded signed transaction
+        :param timeout: timeout in seconds wait for RPC response
         :return:
         """
         return await self.json_rpc(
diff --git a/src/pynear/utils.py b/src/pynear/utils.py
new file mode 100644
index 0000000..7eedbbb
--- /dev/null
+++ b/src/pynear/utils.py
@@ -0,0 +1,9 @@
+from datetime import datetime
+
+
+def utcnow():
+    return datetime.utcnow()
+
+
+def timestamp():
+    return utcnow().timestamp()
\ No newline at end of file