Skip to content

Commit

Permalink
Merge pull request #2 from xeroc/master
Browse files Browse the repository at this point in the history
  • Loading branch information
gileadmcgee committed Oct 23, 2015
2 parents 1393479 + 5e33608 commit 10a0dc5
Show file tree
Hide file tree
Showing 8 changed files with 219 additions and 38 deletions.
5 changes: 3 additions & 2 deletions docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ This library requires `autobahn` and requests to be installed:

.. code-block:: bash
easy_install-3.4 install autobahn
easy_install-3.4 install requests
pip3 install autobahn --user
pip3 install requests --user
pip3 install crypto --user
The graphene library itself can be installed by issuing:

Expand Down
2 changes: 1 addition & 1 deletion docs/pricefeed.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ for the library).
apt-get install python3 python3-pip python-autobahn
pip3 install requests --upgrade
pip3 install numpy prettytable autobahn
pip3 install numpy prettytable autobahn crypto
Cli Wallet
##########
Expand Down
23 changes: 18 additions & 5 deletions grapheneapi/graphenews.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import json
import asyncio
from functools import partial
import ssl

try :
from autobahn.asyncio.websocket import WebSocketClientFactory
Expand All @@ -15,17 +16,23 @@ class GrapheneWebsocket(GrapheneAPI):
""" Constructor takes host, port, and login credentials
"""
def __init__(self, host, port, username, password, proto=GrapheneWebsocketProtocol) :
## initialize API (overwrites __getattr__()
super().__init__(host, port, username, password)

self.username = username
self.password = password
self.host = host
hostparts = host.split("/")
if len(hostparts)==1 :
self.host = hostparts[0]
self.ssl = False
else :
self.host = hostparts[2]
self.ssl = (hostparts[0] == "wss:")
self.port = port
self.proto = proto
self.proto.username = self.username
self.proto.password = self.password

## initialize API (overwrites __getattr__()
super().__init__(host, port, username, password)

""" Get an object_id by name
"""
def object_id(self, name, instance=0) :
Expand Down Expand Up @@ -92,7 +99,13 @@ def getObject(self, oid) :
"""
def run_forever(self) :
loop = asyncio.get_event_loop()
coro = loop.create_connection(self.factory, self.host, self.port)
if self.ssl :
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
coro = loop.create_connection(self.factory, self.host, self.port, ssl=context)
else :
coro = loop.create_connection(self.factory, self.host, self.port, ssl=self.ssl)
loop.run_until_complete(coro)
try :
loop.run_forever()
Expand Down
13 changes: 13 additions & 0 deletions scripts/monitor-refcode/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Monitor Faucet

This script monitors deposits and searches for referral codes of length 8 in the memo.
After that, it makes a API call to the faucet to reserve these funds for later use.

## Configuration

cp config-example.py config.py
# edit config.py

## Run

python3 monitor.py
17 changes: 17 additions & 0 deletions scripts/monitor-refcode/config-example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
""" RPC connection settings """
host = "<websocket host>"
port = 443
user = ""
password = ""

""" Account id to monitor """
accountID = "2.6.XXXX"

""" Memo Key of the receiving account """
memo_wif_key = "<memo-wif-key>"

""" Last operation ID that you have registered in your backend """
last_op = "1.11.0"

""" Faucet settings """
faucet_url = "http://localhost:3000/api/v1/referral_codes", # URL to the faucet
105 changes: 105 additions & 0 deletions scripts/monitor-refcode/monitor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import sys
import json
from grapheneapi import GrapheneWebsocket, GrapheneWebsocketProtocol
from graphenebase import Memo, PrivateKey, PublicKey
import config
import re

try :
import requests
except ImportError:
raise ImportError( "Missing dependency: python-requests" )

""" PubKey Prefix
Productive network: BTS
Testnetwork: GPH """
#prefix = "GPH"
prefix = "BTS"

""" Callback on event
This function will be triggered on a notification of the witness.
If you subsribe (see below) to 2.6.*, the witness node will notify you of
any chances regarding your account_balance """
class GrapheneMonitor(GrapheneWebsocketProtocol) :
last_op = "1.11.0"
account_id = "1"
def __init__(self) :
super().__init__()

def printJson(self,d) : print(json.dumps(d,indent=4))

def onAccountUpdate(self, data) :
# Get Operation ID that modifies our balance
opID = api.getObject(data["most_recent_op"])["operation_id"]
self.wsexec([self.api_ids["history"], "get_account_history", [self.account_id, self.last_op, 100, "1.11.0"]], self.process_operations)
self.last_op = opID

def process_operations(self, operations) :
for operation in operations[::-1] :
opID = operation["id"]
block = operation["block_num"]
op = operation["op"][1]

# Get assets involved in Fee and Transfer
fee_asset = api.getObject(op["fee"]["asset_id"])
amount_asset = api.getObject(op["amount"]["asset_id"])

# Amounts for fee and transfer
fee_amount = op["fee"]["amount"] / float(10**int(fee_asset["precision"]))
amount_amount= op["amount"]["amount"] / float(10**int(amount_asset["precision"]))

# Get accounts involved
from_account = api.getObject(op["from"])
to_account = api.getObject(op["to"])

# Decode the memo
memo = op["memo"]
try : # if possible
privkey = PrivateKey(config.memo_wif_key)
pubkey = PublicKey(memo["from"], prefix=prefix)
memomsg = Memo.decode_memo(privkey, pubkey, memo["nonce"], memo["message"])
except Exception as e: # if not possible
memomsg = "--cannot decode-- (%s)" % str(e)

# Print out
print("last_op: %s | block:%s | from %s -> to: %s | fee: %f %s | amount: %f %s | memo: %s" % (
opID, block,
from_account["name"], to_account["name"],
fee_amount, fee_asset["symbol"],
amount_amount, amount_asset["symbol"],
memomsg))

# Parse the memo
pattern = re.compile('[a-zA-Z0-9]{8}')
searchResults = pattern.search(memomsg)
ref_code = searchResults.group(0)

# Request to Faucet
headers = {'content-type': 'application/json'}
query = {
"refcode[code]" : ref_code,
"refcode[account]" : from_account["name"],
"refcode[asset_symbol]" : amount_asset["symbol"],
"refcode[asset_amount]" : amount_amount,
}
response = requests.get(faucet_url,
data=json.dumps(query),
headers=headers)

if __name__ == '__main__':
## Monitor definitions
protocol = GrapheneMonitor
protocol.last_op = config.last_op ## last operation logged
protocol.account_id = "1.2.%s" % config.accountID.split(".")[2] ## account to monitor

## Open Up Graphene Websocket API
api = GrapheneWebsocket(config.host, config.port, config.user, config.password, protocol)

print(api)

## Set Callback for object changes
api.setObjectCallbacks({config.accountID : protocol.onAccountUpdate})

## Run the Websocket connection continuously
api.connect()
api.run_forever()
15 changes: 9 additions & 6 deletions scripts/pricefeeds/config-example.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
passwd = ""
unlock = ""

ask_confirmation = True

################################################################################
## Delegate Feed Publish Parameters
################################################################################
Expand All @@ -16,17 +18,18 @@
################################################################################
## Fine tuning
################################################################################
discount = 0.995
core_exchange_factor = 1.05 # 5% surplus if paying fees in bitassets

minValidAssetPriceInBTC = 0.00001
change_min = 0.5
discount = 0.995 # discoun for shorts
core_exchange_factor = 0.95 # 5% discount if paying fees in bitassets
maintenance_collateral_ratio = 1750 # Call when collateral only pays off 175% the debt
maximum_short_squeeze_ratio = 1100 # Stop calling when collateral only pays off 110% of the debt
change_min = 0.5 # Percentage of price change to force an update
minValidAssetPriceInBTC = 0.00001# minimum valid price for BTS in BTC

## Enable exchanges
enable_yunbi = True
enable_btc38 = True
enable_bter = False
enable_poloniex = True
enable_poloniex = True
enable_bittrex = True
enable_btcavg = True

Expand Down
Loading

0 comments on commit 10a0dc5

Please sign in to comment.