Skip to content
This repository has been archived by the owner on Nov 16, 2022. It is now read-only.

Commit

Permalink
Merge pull request #2640 from bandprotocol/transaction-module
Browse files Browse the repository at this point in the history
pyband: Add transaction module
  • Loading branch information
taobun authored Sep 14, 2020
2 parents c494fb7 + 71ef45e commit 0aef3ae
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG_UNRELEASED.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@

### Helpers

- (feat) [\#2640](https://github.com/bandprotocol/bandchain/pull/2640) pyband: Transaction module implementation
- (feat) [\#2588](https://github.com/bandprotocol/bandchain/pull/2588) pyband: Auth module implementation
- (impv) [\#2577](https://github.com/bandprotocol/bandchain/pull/2577) Wallet module completion

Expand Down
14 changes: 12 additions & 2 deletions helpers/pyband/pyband/client.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import requests
from dacite import from_dict

from .data import DataSource, OracleScript, RequestInfo, DACITE_CONFIG
from .data import Account, DataSource, OracleScript, RequestInfo, DACITE_CONFIG


class Client(object):
Expand All @@ -11,13 +11,23 @@ def __init__(self, rpc_url: str) -> None:
def _get(self, path, **kwargs):
return requests.get(self.rpc_url + path, **kwargs).json()["result"]

def send_tx(self, data: dict) -> dict:
return requests.post(self.rpc_url + "/txs", json=data).json()

def get_chain_id(self) -> str:
genesis = self._get("/bandchain/genesis")
genesis = requests.get(self.rpc_url + "/bandchain/genesis").json()
return genesis["chain_id"]

def get_latest_block(self) -> dict:
return self._get("/blocks/latest")

def get_account(self, address: str) -> Account:
return from_dict(
data_class=Account,
data=self._get("/auth/accounts/{}".format(address))["value"],
config=DACITE_CONFIG,
)

def get_data_source(self, id: int) -> DataSource:
return from_dict(
data_class=DataSource,
Expand Down
11 changes: 10 additions & 1 deletion helpers/pyband/pyband/data.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import base64
from dataclasses import dataclass
from typing import List
from typing import List, Optional

from dacite import Config

Expand Down Expand Up @@ -89,3 +89,12 @@ class RequestInfo(object):
reports: List[Report]
result: Result


@dataclass
class Account(object):
address: str
coins: List[dict]
public_key: Optional[dict]
account_number: int
sequence: int

84 changes: 84 additions & 0 deletions helpers/pyband/pyband/transaction.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import base64
import json

from .wallet import PrivateKey
from .client import Client


class Transaction:
def __init__(self, client: Client, privkey: PrivateKey):
self.client = client
self.privkey = privkey
self.msgs: list = []
self.chain_id = client.get_chain_id()

def send_tx(
self,
account_num: int,
sequence: int,
gas: int = 200000,
fee: int = 0,
memo: str = "",
mode="sync",
) -> dict:
base64_pubkey = base64.b64encode(bytes.fromhex(self.privkey.to_pubkey().to_hex())).decode(
"utf-8"
)
tx = {
"tx": {
"msg": self.msgs,
"fee": {"gas": str(gas), "amount": [{"denom": "uband", "amount": str(fee)}]},
"memo": memo,
"signatures": [
{
"signature": self._sign(account_num, sequence, gas, fee, memo),
"pub_key": {"type": "tendermint/PubKeySecp256k1", "value": base64_pubkey,},
"account_number": str(account_num),
"sequence": str(sequence),
}
],
},
"mode": mode,
}
return self.client.send_tx(tx)

def add_request(
self, oracle_script_id: int, calldata: bytes, ask_count: int, min_count: int, client_id: str
) -> None:
msg = {
"type": "oracle/Request",
"value": {
"oracle_script_id": str(oracle_script_id),
"calldata": base64.b64encode(calldata).decode("utf-8"),
"ask_count": str(ask_count),
"min_count": str(min_count),
"client_id": client_id,
"sender": self.privkey.to_pubkey().to_address().to_acc_bech32(),
},
}
self.msgs.append(msg)

def _sign(self, account_num: int, sequence: int, gas: int, fee: int, memo: str) -> str:
message_str = json.dumps(
self._get_sign_message(account_num, sequence, gas, fee, memo),
separators=(",", ":"),
sort_keys=True,
)
message_bytes = message_str.encode("utf-8")

signature = self.privkey.sign(message_bytes)

signature_base64_str = base64.b64encode(signature).decode("utf-8")
return signature_base64_str

def _get_sign_message(
self, account_num: int, sequence: int, gas: int, fee: int, memo: str
) -> dict:
return {
"chain_id": self.chain_id,
"account_number": str(account_num),
"fee": {"gas": str(gas), "amount": [{"amount": str(fee), "denom": "uband"}]},
"memo": memo,
"sequence": str(sequence),
"msgs": self.msgs,
}
8 changes: 8 additions & 0 deletions helpers/pyband/pyband/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ def from_mnemonic(cls, words: str, path="m/44'/494'/0'/0/0") -> PrivateKey:
)
return self

@classmethod
def from_hex(cls, priv: str) -> PrivateKey:
self = cls(_error_do_not_use_init_directly=True)
self.signing_key = SigningKey.from_string(
bytes.fromhex(priv), curve=SECP256k1, hashfunc=hashlib.sha256,
)
return self

def to_hex(self) -> str:
"""
Return a hex representation of signing key.
Expand Down
2 changes: 1 addition & 1 deletion helpers/pyband/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
setup(
name="pyband",
packages=["pyband"],
version="0.0.3",
version="0.0.4",
license="MIT",
description="Python library for BandChain",
author="Band Protocol",
Expand Down

0 comments on commit 0aef3ae

Please sign in to comment.