Skip to content

Commit

Permalink
First implementation of xch rpc wallet dealer that includes the main …
Browse files Browse the repository at this point in the history
…functionalities
  • Loading branch information
cripsisxyz committed Jan 25, 2022
0 parents commit 82d83cc
Show file tree
Hide file tree
Showing 12 changed files with 450 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# 0.1.0
* First implementation of xch rpc wallet dealer
12 changes: 12 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[packages]
requests = "*"
pyyaml = "*"

[requires]
python_version = "3"

99 changes: 99 additions & 0 deletions Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

90 changes: 90 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Chia XCH Wallet Dealer

![hello](chia-wallet-dealer.png)

## Description
Welcome to Chia RPC XCH Wallet Dealer. The purpose of this project is fractionate and send XCH of an existing and synced chia wallet (using the Chia RPC Protocol) to multiple wallets destinations, using partitions rules on a config file.
Developed and tested only with the official [chia-blockchain](https://github.com/Chia-Network/chia-blockchain) project.

If you found the project useful, please consider a donation to my chia wallet :)

`xch1vt3g694eclvcjmrj8mq83vtgrva9sw0qdz34muxrqjh5y5fzq6vq89n605`

## Requirements
Attending the official [chia RPC doc](https://docs.chia.net/docs/12rpcs/rpcs/) you need a wallet listening via RPC Protocol, built with a default installation.

You may also need Python interpreter (3.x) installed on your system and it is recommended to use pipenv for installing all libraries dependencys. You can install it with

```bash
pip3 install pipenv
```

## Usage
### The environment
* Install the environment with

```bash
pipenv install
```

* Enter in the environment with

```bash
pipenv shell
```

You can also execute xchdealer without entering in the environment, using `pipenv run python xchdealer.py [params]`, example:

```
pipenv run python xchdealer.py --help
usage: xchdealer.py [-h] -f CONFIG_FILE [-m {simulate,execute}]
...
```
### Edit the config
* Edit config_example.yaml to your needs and rename it if you want

## Config file
Example of config file:
```yaml
---
rpc_connector:
host: "localhost" #Host of the wallet
port: 9256 #Port of the rpc wallet
private_wallet_cert_path: "~/.chia/mainnet/config/ssl/wallet/private_wallet.crt" #Private certificate to connect with RPC
private_wallet_key_path: "~/.chia/mainnet/config/ssl/wallet/private_wallet.key" #Key of the certificate to connect with RP
dealer:
source_wallet:
id: 1 #ID of source wallet, can be identified launching in simulate mode
distribute_percentage_of_total: 100.0 #Percentage of all amount will be distributed, the rest keep on the wallet
fee: 0 #Transaction fee, default 0
destination_wallets:
- name: "iv-vz" #For each destination specify a name
address: "xch1vt3g694eclvcjmrj8mq83vtgrva9sw0qdz34muxrqjh5y5fzq6vq89n605" #Address of the destination wallet
distribution_percentage: 90.0 #Percentage of total amount assigned to this wallet
- name: "alber"
address: "xch1vt3g694eclvcjmrj8mq83vtgrva9sw0qdz34muxrqjh5y5fzq6vq89n605"
distribution_percentage: 10.0

#The sum of all distribution_percentage of destination_wallets must be equal to 100.0
```

## Arguments

### Simulate mode

* You can execute xchdealer in simulate mode to show only the dealing results, check the config or identify the id of source wallet. Run:

```bash
python xchdealer.py -f config_example.yaml -m simulate
```

### Execute mode

* If you are sure of the result, you can execute the real transactions with:

```bash
python xchdealer.py -f config_example.yaml -m execute
```

1 change: 1 addition & 0 deletions VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.1.0
Binary file added chia-wallet-dealer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions config_example.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
rpc_connector:
host: "localhost"
port: 9256
private_wallet_cert_path: "~/.chia/mainnet/config/ssl/wallet/private_wallet.crt"
private_wallet_key_path: "~/.chia/mainnet/config/ssl/wallet/private_wallet.key"

dealer:
source_wallet:
id: 1
distribute_percentage_of_total: 0.1
fee: 0
destination_wallets:
- name: "iv-vz"
address: "xch1vt3g694eclvcjmrj8mq83vtgrva9sw0qdz34muxrqjh5y5fzq6vq89n605"
distribution_percentage: 100.0
Empty file added lib/dealermath/__init.py__
Empty file.
25 changes: 25 additions & 0 deletions lib/dealermath/dealermath.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
class DealerMath():

@staticmethod
def mojo_to_xch_str(mojos=int):
max_send_amount_xch = (mojos / 1000000000000)
return(f'{max_send_amount_xch:.12f}')

@staticmethod
def calculate_proportion(total_amount=int, percentage=float):
if DealerMath.is_between(0.0, percentage, 100.0):
return(int((percentage / 100) * total_amount))
else:
raise Exception(f"Percentage values must be between 0.0 and 100.0! Specified: {str(percentage)}")

@staticmethod
def check_sum(sum_elements=list, expected_total_value=float):
if all(isinstance(x, float) for x in sum_elements):
if sum(sum_elements) != expected_total_value:
raise Exception(f"The sum of {str(' + '.join(map(str, sum_elements)))} is not equal to {str(expected_total_value)}!")
else:
raise Exception(f"NOT all percentage values are written as floats!")

@staticmethod
def is_between(a, x, b):
return min(a, b) <= x <= max(a, b)
Empty file added lib/rpc/__init.py__
Empty file.
92 changes: 92 additions & 0 deletions lib/rpc/xchrpc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import logging, requests, json
from os.path import expanduser
from requests.packages.urllib3.exceptions import InsecureRequestWarning
from lib.dealermath.dealermath import DealerMath

class RemoteProcedureCall():

def __init__(self, host="localhost", port=9256, private_wallet_cert_path="~/.chia/mainnet/config/ssl/wallet/private_wallet.crt", private_wallet_key_path="~/.chia/mainnet/config/ssl/wallet/private_wallet.key"):
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

self.default_rpc_headers = {'Content-Type': 'application/json'}
self.default_wallet_certs = (expanduser(private_wallet_cert_path), expanduser(private_wallet_key_path))
self.host = host
self.port = port

logging.info(f"RPC connector set to {self.host}:{str(self.port)} using certs {str(self.default_wallet_certs)}")


def check_available_wallets(self):
logging.info('Checking available RPC chia wallets')

request_data = {"wallet_id": "*"}
try:
response = requests.post(f"https://{self.host}:{str(self.port)}/get_wallets", headers=self.default_rpc_headers, json=request_data, cert=self.default_wallet_certs, verify=False)
response.raise_for_status()
except Exception as e:
logging.error(f"Cannot get available RPC chia wallets {str(e)}")
return(False)
else:
available_wallets = json.loads(response.text)['wallets']
logging.info(f"Connection with chia RPC protocol sucessfull")
logging.info(f"Available wallets: {available_wallets}")
return(available_wallets)

def check_wallets_synced(self):
logging.info(f"Checking chia wallets synced")

request_data = {}
try:
response = requests.post(f"https://{self.host}:{str(self.port)}/get_sync_status", headers=self.default_rpc_headers, json=request_data, cert=self.default_wallet_certs, verify=False)
response.raise_for_status()
except Exception as e:
logging.error(f"Cannot get RPC chia wallets sync status {str(e)}")
return(False)
else:
loaded_json = json.loads(response.text)
if loaded_json["syncing"]:
logging.info(f"Wallets are syncing with network")
else:
logging.info(f"Wallets are NOT syncing with network")

if loaded_json["synced"]:
logging.info(f"Wallets are correctly synced with network")
else:
logging.warning(f"Wallets are NOT synced with network")
return(False)

def check_wallet_balance(self, wallet_id=int):
logging.info(f"Checking XCH balance on wallet id {str(wallet_id)}")

request_data = {"wallet_id": wallet_id}
try:
response = requests.post(f"https://{self.host}:{str(self.port)}/get_wallet_balance", headers=self.default_rpc_headers, json=request_data, cert=self.default_wallet_certs, verify=False)
response.raise_for_status()
except Exception as e:
logging.error(f"Cannot get available RPC chia wallets {str(e)}")
return(False)
else:
max_send_amount_mojo = int(json.loads(response.text)["wallet_balance"]["max_send_amount"])
max_send_amount_xch_str = DealerMath.mojo_to_xch_str(max_send_amount_mojo)
logging.info(f"Available balance for sending (max_send_amount): {str(max_send_amount_mojo)} MOJOs == {str(max_send_amount_xch_str)} XCH")

return(max_send_amount_mojo, max_send_amount_xch_str)

def send_wallet_transaction(self, source_wallet_id=int, amount=int, destination_wallet_address=str, fee=0):
logging.info(f"Sending {str(amount)} MOJO to address {destination_wallet_address}")

request_data = {
"wallet_id": source_wallet_id,
"amount": amount,
"address": destination_wallet_address,
"fee": fee
}
try:
response = requests.post(f"https://{self.host}:{str(self.port)}/send_transaction", headers=self.default_rpc_headers, json=request_data, cert=self.default_wallet_certs, verify=False)
response.raise_for_status()
except Exception as e:
logging.error(str(e))
return(False)

logging.info(response.text)

Loading

0 comments on commit 82d83cc

Please sign in to comment.