Skip to content

Commit 5102aec

Browse files
Merge pull request #14 from dragonchain/master
Release 4.1.0
2 parents c10dddf + 9a69fcf commit 5102aec

File tree

9 files changed

+412
-36
lines changed

9 files changed

+412
-36
lines changed

docs/changelog.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
Changelog
22
=========
33

4+
4.1.0
5+
-----
6+
7+
Features:
8+
* Add Binance interchain support
9+
Development:
10+
* Add integration tests for Binance feature
11+
* Add/Update integration tests for Dragonchain 4.2.0
12+
413
4.0.1
514
-----
615

dragonchain_sdk/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from dragonchain_sdk import dragonchain_client
1717

1818
__author__ = "Dragonchain, Inc."
19-
__version__ = "4.0.1"
19+
__version__ = "4.1.0"
2020

2121
ASYNC_SUPPORT = False
2222

dragonchain_sdk/dragonchain_client.py

Lines changed: 159 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ def get_transaction(self, transaction_id: str) -> "request_response":
391391
The transaction searched for
392392
"""
393393
if not isinstance(transaction_id, str):
394-
raise TypeError('Paramter "transaction_id" must be of type str.')
394+
raise TypeError('Parameter "transaction_id" must be of type str.')
395395
return self.request.get("/v1/transaction/{}".format(transaction_id))
396396

397397
def create_transaction(
@@ -727,7 +727,7 @@ def create_bitcoin_interchain(
727727
728728
Args:
729729
name (str): The name to use for this network. Will overwrite if providing a name that already exists
730-
testnet (bool): Whether or not this is a testnet wallet/address (not required if providing private_key as WIF)
730+
testnet (bool, optional): Whether or not this is a testnet wallet/address (not required if providing private_key as WIF)
731731
private_key (str, optional): The base64 encoded private key, or WIF for the desired wallet. Will generate randomly if not provided
732732
rpc_address (str, optional): The endpoint of the bitcoin core RPC node to use (i.e. http://my-node:8332)
733733
rpc_authorization (str, optional): The base64-encoded username:password for the rpc node. For example, user: a pass: b would be 'YTpi' (base64("a:b"))
@@ -946,6 +946,128 @@ def sign_ethereum_transaction(
946946
transaction = _build_ethereum_transaction_body(to=to, value=value, data=data, gas_price=gas_price, gas=gas, nonce=nonce)
947947
return self.request.post("/v1/interchains/ethereum/{}/transaction".format(name), transaction)
948948

949+
def create_binance_interchain(
950+
self,
951+
name: str,
952+
testnet: Optional[bool] = None,
953+
private_key: Optional[str] = None,
954+
node_url: Optional[str] = None,
955+
rpc_port: Optional[int] = None,
956+
api_port: Optional[int] = None,
957+
) -> "request_response":
958+
"""Create (or overwrite) a binance wallet/network for interchain use
959+
960+
Args:
961+
name (str): The name to use for this network. Will overwrite if providing a name that already exists
962+
testnet (bool, optional): Whether or not this is a testnet wallet/address. Defaults to True.
963+
private_key (str, optional): The base64 or hex encoded private key. Will generate randomly if not provided
964+
node_url (str, optional): The endpoint of the binance RPC node to use (i.e. http://my.node.address)
965+
rpc_port (int, optional): The port being used to hit the RPC endpoints (i.e. 27147)
966+
api_port (int, optional): The port being used to hit the API endpoints (i.e. 1169)
967+
968+
Raises:
969+
TypeError: with bad parameters
970+
971+
Returns:
972+
The created interchain network
973+
"""
974+
if not isinstance(name, str):
975+
raise TypeError('Parameter "name" must be of type str.')
976+
if testnet is not None and not isinstance(testnet, bool):
977+
raise TypeError('Parameter "testnet" must be of type bool.')
978+
if private_key is not None and not isinstance(private_key, str):
979+
raise TypeError('Parameter "private_key" must be of type str.')
980+
if node_url is not None and not isinstance(node_url, str):
981+
raise TypeError('Parameter "node_url" must be of type str.')
982+
if rpc_port is not None and not isinstance(rpc_port, int):
983+
raise TypeError('Parameter "rpc_port" must be of type str.')
984+
if api_port is not None and not isinstance(api_port, int):
985+
raise TypeError('Parameter "api_port" must be of type str.')
986+
body = cast(Dict[str, Any], {"version": "1", "name": name})
987+
if testnet is not None:
988+
body["testnet"] = testnet
989+
if private_key:
990+
body["private_key"] = private_key
991+
if node_url:
992+
body["node_url"] = node_url
993+
if rpc_port:
994+
body["rpc_port"] = rpc_port
995+
if api_port:
996+
body["api_port"] = api_port
997+
return self.request.post("/v1/interchains/binance", body)
998+
999+
def update_binance_interchain(
1000+
self,
1001+
name: str,
1002+
testnet: Optional[bool] = None,
1003+
private_key: Optional[str] = None,
1004+
node_url: Optional[str] = None,
1005+
rpc_port: Optional[int] = None,
1006+
api_port: Optional[int] = None,
1007+
) -> "request_response":
1008+
"""Update an existing binance wallet/network for interchain use
1009+
1010+
Args:
1011+
name (str): The name of the network to update
1012+
testnet (bool): Whether or not this is a testnet wallet/address
1013+
private_key (str, optional): The base64 or hex encoded private key. Will generate randomly if not provided
1014+
node_url (str, optional): The endpoint of the binance RPC node to use (i.e. http://my.node.address)
1015+
rpc_port (int, optional): The port being used to hit the RPC endpoints (i.e. 27147)
1016+
api_port (int, optional): The port being used to hit the API endpoints (i.e. 1169)
1017+
1018+
Raises:
1019+
TypeError: with bad parameters
1020+
1021+
Returns:
1022+
The updated interchain network
1023+
"""
1024+
if not isinstance(name, str):
1025+
raise TypeError('Parameter "name" must be of type str.')
1026+
if testnet is not None and not isinstance(testnet, bool):
1027+
raise TypeError('Parameter "testnet" must be of type bool.')
1028+
if private_key is not None and not isinstance(private_key, str):
1029+
raise TypeError('Parameter "private_key" must be of type str.')
1030+
if node_url is not None and not isinstance(node_url, str):
1031+
raise TypeError('Parameter "node_url" must be of type str.')
1032+
if rpc_port is not None and not isinstance(rpc_port, int):
1033+
raise TypeError('Parameter "rpc_port" must be of type str.')
1034+
if api_port is not None and not isinstance(api_port, int):
1035+
raise TypeError('Parameter "api_port" must be of type str.')
1036+
body = cast(Dict[str, Any], {"version": "1"})
1037+
if testnet is not None:
1038+
body["testnet"] = testnet
1039+
if private_key:
1040+
body["private_key"] = private_key
1041+
if node_url:
1042+
body["node_url"] = node_url
1043+
if rpc_port:
1044+
body["rpc_port"] = rpc_port
1045+
if api_port:
1046+
body["api_port"] = api_port
1047+
return self.request.patch("/v1/interchains/binance/{}".format(name), body)
1048+
1049+
def sign_binance_transaction(
1050+
self, name: str, amount: int, to_address: str, symbol: Optional[str] = None, memo: Optional[str] = None
1051+
) -> "request_response":
1052+
"""Create and sign a binance transaction using your chain's interchain network
1053+
1054+
Args:
1055+
name (str): name of the binance network to use for signing
1056+
amount (int): amount of token in transaction
1057+
to_address (str): hex of the address to send to
1058+
symbol (str, optional): the exchange symbol for the token (defaults to BNB)
1059+
memo (str, optional): string of data to publish in the transaction (defaults to "")
1060+
Raises:
1061+
TypeError: with bad parameter types
1062+
1063+
Returns:
1064+
The built and signed transaction
1065+
"""
1066+
if not isinstance(name, str):
1067+
raise TypeError('Parameter "name" must be of type str.')
1068+
transaction = _build_binance_transaction_body(symbol=symbol, amount=amount, to_address=to_address, memo=memo)
1069+
return self.request.post("/v1/interchains/binance/{}/transaction".format(name), transaction)
1070+
9491071
def get_interchain_network(self, blockchain: str, name: str) -> "request_response":
9501072
"""Get a configured interchain network/wallet from the chain
9511073
@@ -1116,7 +1238,7 @@ def get_public_blockchain_addresses(self) -> "request_response":
11161238

11171239

11181240
def _validate_and_build_custom_index_fields_array( # noqa: C901
1119-
custom_index_fields: Iterable["custom_index_fields_type"]
1241+
custom_index_fields: Iterable["custom_index_fields_type"],
11201242
) -> List["custom_index_fields_type"]:
11211243
"""Validate a list of custom index fields and return a list which can be passed as a body for custom indexes to the chain
11221244
@@ -1300,3 +1422,37 @@ def _build_bitcoin_transaction_body(
13001422
body["change"] = change_address
13011423

13021424
return body
1425+
1426+
1427+
def _build_binance_transaction_body(amount: int, to_address: str, symbol: Optional[str] = None, memo: Optional[str] = None) -> Dict[str, Any]:
1428+
"""Build the json (dictionary) body for a binance transaction given its inputs
1429+
1430+
Args:
1431+
amount (int): amount of token in transaction
1432+
to_address (str): hex of the address to send to
1433+
symbol (str, optional): the exchange symbol for the token (defaults to BNB)
1434+
memo (str, optional): string of data to publish in the transaction (defaults to "")
1435+
1436+
Raises:
1437+
TypeError: with bad parameter types
1438+
1439+
Returns:
1440+
Dictionary body to use for sending a binance transaction
1441+
"""
1442+
1443+
if not isinstance(amount, int):
1444+
raise TypeError('Parameter "amount" must be of type int.')
1445+
if not isinstance(to_address, str):
1446+
raise TypeError('Parameter "to_address" must be of type str.')
1447+
if symbol is not None and not isinstance(symbol, str):
1448+
raise TypeError('Parameter "symbol" must be of type str.')
1449+
if memo is not None and not isinstance(memo, str):
1450+
raise TypeError('Parameter "memo" must be of type str.')
1451+
1452+
body = cast(Dict[str, Any], {"version": "1", "amount": amount, "to_address": to_address})
1453+
if symbol:
1454+
body["symbol"] = symbol
1455+
if memo:
1456+
body["memo"] = memo
1457+
1458+
return body

tests/integration/schema.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,13 @@
144144
"additionalProperties": False,
145145
}
146146

147+
created_binance_transaction_schema = {
148+
"type": "object",
149+
"properties": {"signed": {"type": "string", "pattern": "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$"}},
150+
"required": ["signed"],
151+
"additionalProperties": False,
152+
}
153+
147154
create_transaction_schema = {
148155
"type": "object",
149156
"properties": {"transaction_id": {"type": "string", "pattern": _uuidv4_regex}},
@@ -193,6 +200,29 @@
193200
"additionalProperties": False,
194201
}
195202

203+
binance_interchain_at_rest_schema = {
204+
"type": "object",
205+
"properties": {
206+
"version": {"type": "string", "enum": ["1"]},
207+
"blockchain": {"type": "string", "enum": ["binance"]},
208+
"testnet": {"type": "boolean"},
209+
"name": {"type": "string"},
210+
"node_url": {"type": "string"},
211+
"rpc_port": {"type": "integer"},
212+
"api_port": {"type": "integer"},
213+
"address": {"type": "string"},
214+
},
215+
"required": ["version", "blockchain", "testnet", "name", "node_url", "rpc_port", "api_port", "address"],
216+
"additionalProperties": False,
217+
}
218+
219+
binance_interchain_list_schema = {
220+
"type": "object",
221+
"properties": {"interchains": {"type": "array", "items": binance_interchain_at_rest_schema}},
222+
"required": ["interchains"],
223+
"additionalProperties": False,
224+
}
225+
196226
bulk_create_transaction_schema = {
197227
"type": "object",
198228
"properties": {

tests/integration/test_blocks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def test_query_blocks_by_timestamp(self):
7070
)
7171

7272
def test_query_blocks_by_id(self):
73-
current_block = int((time.time() - 1432238220) / 5)
73+
current_block = int((time.time() - 1432238220) / 5) + 1
7474
response1 = self.client.query_blocks("@block_id:[-inf {}]".format(current_block), sort_by="block_id", sort_ascending=True)
7575
response2 = self.client.query_blocks("@block_id:[-inf {}]".format(current_block), sort_by="block_id", sort_ascending=False)
7676
response3 = self.client.query_blocks("@block_id:[{} +inf]".format(current_block)) # Should not return any results

0 commit comments

Comments
 (0)