Skip to content

Commit 83d4919

Browse files
committed
Merge branch 'release/0.2.1'
2 parents 80aabb4 + 2ca4554 commit 83d4919

File tree

11 files changed

+335
-172
lines changed

11 files changed

+335
-172
lines changed

bitshares/dex.py

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,19 @@ def close_debt_position(self, symbol, account=None):
149149
})
150150
return self.blockchain.finalizeOp(op, account["name"], "active")
151151

152-
def adjust_debt(self, delta, new_collateral_ratio=None, account=None):
152+
def adjust_debt(self, delta, new_collateral_ratio=None, account=None, target_collateral_ratio=None):
153153
""" Adjust the amount of debt for an asset
154154
155-
:param Amount delta: Delta amount of the debt (-10 means reduce debt by 10, +10 means borrow another 10)
156-
:param float new_collateral_ratio: collateral ratio to maintain (optional, by default tries to maintain old ratio)
155+
:param Amount delta: Delta amount of the debt (-10 means reduce
156+
debt by 10, +10 means borrow another 10)
157+
:param float new_collateral_ratio: collateral ratio to maintain
158+
(optional, by default tries to maintain old ratio)
159+
:param float target_collateral_ratio: Tag the call order so that in
160+
case of margin call, only enough debt is covered to get back to
161+
this ratio
157162
:raises ValueError: if symbol is not a bitasset
158-
:raises ValueError: if collateral ratio is smaller than maintenance collateral ratio
163+
:raises ValueError: if collateral ratio is smaller than maintenance
164+
collateral ratio
159165
:raises ValueError: if required amounts of collateral are not available
160166
"""
161167
if not account:
@@ -178,14 +184,11 @@ def adjust_debt(self, delta, new_collateral_ratio=None, account=None):
178184

179185
# Check minimum collateral ratio
180186
backing_asset_id = bitasset["options"]["short_backing_asset"]
181-
# maintenance_col_ratio = bitasset["current_feed"]["maintenance_collateral_ratio"] / 1000
182187
current_debts = self.list_debt_positions(account)
183188
if not new_collateral_ratio and symbol not in current_debts:
184-
new_collateral_ratio = maintenance_col_ratio
189+
new_collateral_ratio = bitasset["current_feed"]["maintenance_collateral_ratio"] / 1000
185190
elif not new_collateral_ratio and symbol in current_debts:
186191
new_collateral_ratio = current_debts[symbol]["ratio"]
187-
# if maintenance_col_ratio > new_collateral_ratio:
188-
# raise ValueError("Collateral Ratio has to be higher than %5.2f" % maintenance_col_ratio)
189192

190193
# Derive Amount of Collateral
191194
collateral_asset = Asset(
@@ -212,7 +215,7 @@ def adjust_debt(self, delta, new_collateral_ratio=None, account=None):
212215
raise ValueError("Not enough funds available. Need %f %s, but only %f %s are available" %
213216
(fundsNeeded, collateral_asset["symbol"], fundsHave, collateral_asset["symbol"]))
214217

215-
op = operations.Call_order_update(**{
218+
payload = {
216219
'fee': {'amount': 0, 'asset_id': '1.3.0'},
217220
'delta_debt': {
218221
'amount': int(float(delta) * 10 ** asset["precision"]),
@@ -221,15 +224,25 @@ def adjust_debt(self, delta, new_collateral_ratio=None, account=None):
221224
'amount': int(float(amount_of_collateral) * 10 ** collateral_asset["precision"]),
222225
'asset_id': collateral_asset["id"]},
223226
'funding_account': account["id"],
224-
'extensions': []
225-
})
227+
'extensions': {}
228+
}
229+
# Extension
230+
if target_collateral_ratio:
231+
payload["extensions"].update(dict(
232+
target_collateral_ratio=int(target_collateral_ratio * 100)
233+
))
234+
235+
op = operations.Call_order_update(**payload)
226236
return self.blockchain.finalizeOp(op, account["name"], "active")
227237

228-
def adjust_collateral_ratio(self, symbol, target_collateral_ratio, account=None):
238+
def adjust_collateral_ratio(self, symbol, new_collateral_ratio, account=None, target_collateral_ratio=None):
229239
""" Adjust the collataral ratio of a debt position
230240
231241
:param Asset amount: Amount to borrow (denoted in 'asset')
232-
:param float target_collateral_ratio: desired collateral ratio
242+
:param float new_collateral_ratio: desired collateral ratio
243+
:param float target_collateral_ratio: Tag the call order so that in
244+
case of margin call, only enough debt is covered to get back to
245+
this ratio
233246
:raises ValueError: if symbol is not a bitasset
234247
:raises ValueError: if collateral ratio is smaller than maintenance collateral ratio
235248
:raises ValueError: if required amounts of collateral are not available
@@ -243,17 +256,20 @@ def adjust_collateral_ratio(self, symbol, target_collateral_ratio, account=None)
243256
current_debts = self.list_debt_positions(account)
244257
if symbol not in current_debts:
245258
raise ValueError("No Call position available to adjust! Please borrow first!")
246-
return self.adjust_debt(Amount(0, symbol), target_collateral_ratio, account)
259+
return self.adjust_debt(Amount(0, symbol), new_collateral_ratio, account, target_collateral_ratio=target_collateral_ratio)
247260

248-
def borrow(self, amount, collateral_ratio=None, account=None):
261+
def borrow(self, amount, collateral_ratio=None, account=None, target_collateral_ratio=None):
249262
""" Borrow bitassets/smartcoins from the network by putting up
250263
collateral in a CFD at a given collateral ratio.
251264
252265
:param float amount: Amount to borrow (denoted in 'asset')
253266
:param float collateral_ratio: Collateral ratio to borrow at
267+
:param float target_collateral_ratio: Tag the call order so that in
268+
case of margin call, only enough debt is covered to get back to
269+
this ratio
254270
:raises ValueError: if symbol is not a bitasset
255271
:raises ValueError: if collateral ratio is smaller than maintenance collateral ratio
256272
:raises ValueError: if required amounts of collateral are not available
257273
258274
"""
259-
return self.adjust_debt(amount, collateral_ratio, account)
275+
return self.adjust_debt(amount, collateral_ratio, account, target_collateral_ratio=target_collateral_ratio)

bitshares/message.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@
4444
"""
4545

4646

47-
class Message():
47+
class Message(BlockchainInstance):
4848

49-
def __init__(self, message, **kwargs):
50-
BlockchainInstance.__init__(self, **kwargs)
49+
def __init__(self, message, *args, **kwargs):
50+
BlockchainInstance.__init__(self, *args, **kwargs)
5151
self.message = message
5252

5353
def sign(self, account=None, **kwargs):

bitshares/wallet.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,12 +142,14 @@ def created(self):
142142
def create(self, pwd):
143143
""" Alias for newWallet()
144144
"""
145-
pass
145+
self.newWallet(pwd)
146146

147147
def newWallet(self, pwd):
148148
""" Create a new wallet database
149149
"""
150-
pass
150+
if self.created():
151+
raise WalletExists("You already have created a wallet!")
152+
self.store.unlock(pwd)
151153

152154
def addPrivateKey(self, wif):
153155
""" Add a private key to the wallet database

bitsharesbase/account.py

Lines changed: 148 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,151 @@
11
from graphenebase.account import (
2-
PasswordKey,
3-
BrainKey,
4-
Address,
5-
PublicKey,
6-
PrivateKey,
7-
Prefix
2+
PasswordKey as GPHPasswordKey,
3+
BrainKey as GPHBrainKey,
4+
Address as GPHAddress,
5+
PublicKey as GPHPublicKey,
6+
PrivateKey as GPHPrivateKey
87
)
98

10-
# Redefine default prefix
11-
Prefix.prefix = "BTS"
9+
import sys
10+
import hashlib
11+
from binascii import hexlify, unhexlify
12+
13+
14+
class PasswordKey(GPHPasswordKey):
15+
""" This class derives a private key given the account name, the
16+
role and a password. It leverages the technology of Brainkeys
17+
and allows people to have a secure private key by providing a
18+
passphrase only.
19+
"""
20+
21+
def __init__(self, *args, **kwargs):
22+
super(PasswordKey, self).__init__(*args, **kwargs)
23+
24+
# overloaded from GHPPasswordKey, JUST to set prefix='BTS' :(
25+
def get_private(self):
26+
""" Derive private key from the brain key and the current sequence
27+
number
28+
"""
29+
if sys.version > '3':
30+
a = bytes(self.account + self.role + self.password, 'utf8')
31+
else:
32+
a = bytes(self.account + self.role + self.password).encode('utf8')
33+
s = hashlib.sha256(a).digest()
34+
return PrivateKey(hexlify(s).decode('ascii'))
35+
36+
37+
class BrainKey(GPHBrainKey):
38+
"""Brainkey implementation similar to the graphene-ui web-wallet.
39+
40+
:param str brainkey: Brain Key
41+
:param int sequence: Sequence number for consecutive keys
42+
43+
Keys in Graphene are derived from a seed brain key which is a string of
44+
16 words out of a predefined dictionary with 49744 words. It is a
45+
simple single-chain key derivation scheme that is not compatible with
46+
BIP44 but easy to use.
47+
48+
Given the brain key, a private key is derived as::
49+
50+
privkey = SHA256(SHA512(brainkey + " " + sequence))
51+
52+
Incrementing the sequence number yields a new key that can be
53+
regenerated given the brain key.
54+
"""
55+
56+
def __init__(self, *args, **kwargs):
57+
super(BrainKey, self).__init__(*args, **kwargs)
58+
59+
# overloaded from GHPBrainKey, JUST to set prefix='BTS' :(
60+
def get_private(self):
61+
""" Derive private key from the brain key and the current sequence
62+
number
63+
"""
64+
encoded = "%s %d" % (self.brainkey, self.sequence)
65+
if sys.version > '3':
66+
a = bytes(encoded, 'ascii')
67+
else:
68+
a = bytes(encoded).encode('ascii')
69+
s = hashlib.sha256(hashlib.sha512(a).digest()).digest()
70+
return PrivateKey(hexlify(s).decode('ascii'))
71+
72+
def get_blind_private(self):
73+
""" Derive private key from the brain key (and no sequence number)
74+
"""
75+
if sys.version > '3':
76+
a = bytes(self.brainkey, 'ascii')
77+
else:
78+
a = bytes(self.brainkey).encode('ascii')
79+
return PrivateKey(hashlib.sha256(a).hexdigest())
80+
81+
82+
class Address(GPHAddress):
83+
""" Address class
84+
85+
This class serves as an address representation for Public Keys.
86+
87+
:param str address: Base58 encoded address (defaults to ``None``)
88+
:param str pubkey: Base58 encoded pubkey (defaults to ``None``)
89+
:param str prefix: Network prefix (defaults to ``BTS``)
90+
91+
Example::
92+
93+
Address("BTSFN9r6VYzBK8EKtMewfNbfiGCr56pHDBFi")
94+
95+
"""
96+
def __init__(self, *args, **kwargs):
97+
if "prefix" not in kwargs:
98+
kwargs["prefix"] = "BTS" # make prefix BTS
99+
super(Address, self).__init__(*args, **kwargs)
100+
101+
102+
class PublicKey(GPHPublicKey):
103+
""" This class deals with Public Keys and inherits ``Address``.
104+
105+
:param str pk: Base58 encoded public key
106+
:param str prefix: Network prefix (defaults to ``BTS``)
107+
108+
Example:::
109+
110+
PublicKey("BTS6UtYWWs3rkZGV8JA86qrgkG6tyFksgECefKE1MiH4HkLD8PFGL")
111+
112+
.. note:: By default, graphene-based networks deal with **compressed**
113+
public keys. If an **uncompressed** key is required, the
114+
method ``unCompressed`` can be used::
115+
116+
PublicKey("xxxxx").unCompressed()
117+
118+
"""
119+
def __init__(self, *args, **kwargs):
120+
if "prefix" not in kwargs:
121+
kwargs["prefix"] = "BTS" # make prefix BTS
122+
super(PublicKey, self).__init__(*args, **kwargs)
123+
124+
125+
class PrivateKey(GPHPrivateKey):
126+
""" Derives the compressed and uncompressed public keys and
127+
constructs two instances of ``PublicKey``:
128+
129+
:param str wif: Base58check-encoded wif key
130+
:param str prefix: Network prefix (defaults to ``BTS``)
131+
132+
Example:::
133+
134+
PrivateKey("5HqUkGuo62BfcJU5vNhTXKJRXuUi9QSE6jp8C3uBJ2BVHtB8WSd")
135+
136+
Compressed vs. Uncompressed:
137+
138+
* ``PrivateKey("w-i-f").pubkey``:
139+
Instance of ``PublicKey`` using compressed key.
140+
* ``PrivateKey("w-i-f").pubkey.address``:
141+
Instance of ``Address`` using compressed key.
142+
* ``PrivateKey("w-i-f").uncompressed``:
143+
Instance of ``PublicKey`` using uncompressed key.
144+
* ``PrivateKey("w-i-f").uncompressed.address``:
145+
Instance of ``Address`` using uncompressed key.
146+
147+
"""
148+
def __init__(self, *args, **kwargs):
149+
if "prefix" not in kwargs:
150+
kwargs["prefix"] = "BTS" # make prefix BTS
151+
super(PrivateKey, self).__init__(*args, **kwargs)

0 commit comments

Comments
 (0)