Skip to content

Commit baf7f1e

Browse files
committed
Merge branch 'release/0.7.0'
2 parents afb0b43 + 47d80a5 commit baf7f1e

8 files changed

Lines changed: 339 additions & 5 deletions

File tree

.changes/0.7.0.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[
2+
{
3+
"description": "Add liquidity pool support",
4+
"type": "minor"
5+
}
6+
]

AUTHORS

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
409 Fabian Schuh <Fabian@chainsquad.com>
2-
213 Fabian Schuh <mail@xeroc.org>
2+
215 Fabian Schuh <mail@xeroc.org>
33
127 Vladimir Kamarzin <vvk@vvk.pp.ru>
4-
97 Fabian Schuh <xeroc@chainsquad.com>
4+
94 Fabian Schuh <xeroc@chainsquad.com>
55
68 pyup-bot <github-bot@pyup.io>
66
27 jhtitor <john.titor@openmailbox.org>
7+
11 Christopher Sanborn <23085117+christophersanborn@users.noreply.github.com>
78
4 Chris Beaven <smileychris@gmail.com>
8-
4 Christopher Sanborn <23085117+christophersanborn@users.noreply.github.com>
99
4 Stefan Schiessl <stefan.schiessl@blockchainprojectsbv.com>
1010
3 Mika Koivistoinen <mika@codaone.fi>
1111
3 RuneStone <rtk@rtk-cv.dk>
1212
2 Rune <rtk@rtk-cv.dk>
1313
2 Stefan Schießl <stefan.schiessl@blockchainprojectsbv.com>
1414
2 Zapata <marco.tessari@gmail.com>
1515
2 brickgao <brickgao@gmail.com>
16+
1 Abit <abitmore@users.noreply.github.com>
1617
1 Alexey Alexeyev <algruun@gmail.com>
1718
1 BrianZhang <tianyekuo@hotmail.com>
1819
1 BroncoTc <i@broncotc.net>

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# Changelog
22
Note: version releases in the 0.x.y range may introduce breaking changes.
33

4+
## 0.7.0
5+
6+
- minor: Add liquidity pool support
7+
48
## 0.6.0
59

610
- minor: Add support for tickets

bitshares/bitshares.py

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1764,3 +1764,211 @@ def update_voting_ticket(self, ticket_id, new_target_type, amount_to_update,
17641764
}
17651765
)
17661766
return self.finalizeOp(op, account, "active", **kwargs)
1767+
1768+
1769+
def create_liquidity_pool(self, asset_a, asset_b, share_asset,
1770+
taker_fee_percent, withdrawal_fee_percent,
1771+
account=None, **kwargs):
1772+
"""Create a liquidity pool
1773+
1774+
:param str asset_a: First asset in the pool pair.
1775+
:param str asset_b: Second asset in the pool pair.
1776+
:param str share_asset: The asset which represents shares in the pool.
1777+
1778+
For asset parameters, these can be either symbols or asset_id
1779+
strings. Note that network expects asset_a to have a lower-numbered
1780+
asset_id than asset_b.
1781+
1782+
:param float taker_fee_percent: The pool's taker fee percentage.
1783+
:param float withdrawal_fee_percent: The pool's withdrawal fee percent.
1784+
1785+
For percentages, meaningful range is [0.00, 100.00], where 1% is
1786+
represented as 1.0. Smallest non-zero value recognized by BitShares
1787+
chain is 0.01 for 0.01%.
1788+
1789+
"""
1790+
if not account:
1791+
if "default_account" in self.config:
1792+
account = self.config["default_account"]
1793+
if not account:
1794+
raise ValueError("You need to provide an account")
1795+
account = Account(account, blockchain_instance=self)
1796+
1797+
asset_a = Asset(asset_a)["id"]
1798+
asset_b = Asset(asset_b)["id"]
1799+
share_asset = Asset(share_asset)["id"]
1800+
1801+
if not (taker_fee_percent >=0 and taker_fee_percent <= 100):
1802+
raise ValueError("Percentages must be in range [0.00, 100.00].")
1803+
if not (withdrawal_fee_percent >=0 and withdrawal_fee_percent <= 100):
1804+
raise ValueError("Percentages must be in range [0.00, 100.00].")
1805+
graphene_1_percent = 100
1806+
taker_fee_percent = int(taker_fee_percent * graphene_1_percent)
1807+
withdrawal_fee_percent = int(withdrawal_fee_percent * graphene_1_percent)
1808+
1809+
op = operations.Liquidity_pool_create(
1810+
**{
1811+
"fee": {"amount": 0, "asset_id": "1.3.0"},
1812+
"account": account["id"],
1813+
"asset_a": asset_a,
1814+
"asset_b": asset_b,
1815+
"share_asset": share_asset,
1816+
"taker_fee_percent": taker_fee_percent,
1817+
"withdrawal_fee_percent": withdrawal_fee_percent,
1818+
"extensions": [],
1819+
}
1820+
)
1821+
return self.finalizeOp(op, account, "active", **kwargs)
1822+
1823+
1824+
def _find_liquidity_pool(self, pool):
1825+
# Ad-hoc helper for the liquidity pool verbs. It locates a pool id
1826+
# irrespective of whether 'pool' is already a pool id, or perhaps an
1827+
# asset or asset_id of a share asset for a pool. The approach is
1828+
# ad-hoc. Would be better if there was a Pool class to represent pool
1829+
# objects like there is an Asset class to represent asset objects.
1830+
# Then locating a pool could happen in the initialization of the Pool
1831+
# object given either an id or asset/symbol. TBD someday.
1832+
if isinstance(pool, str) and pool.startswith("1.19."):
1833+
pool_id = pool
1834+
else:
1835+
try:
1836+
pool_asset = Asset(pool, blockchain_instance=self)
1837+
except:
1838+
raise ValueError("'pool' is neither a pool id nor share asset.")
1839+
if "for_liquidity_pool" in pool_asset:
1840+
pool_id = pool_asset["for_liquidity_pool"]
1841+
else:
1842+
raise ValueError("Asset is not a share asset for a pool.")
1843+
return pool_id
1844+
1845+
1846+
def delete_liquidity_pool(self, pool, account=None, **kwargs):
1847+
"""Delete a liquidity pool
1848+
1849+
:param str,Asset pool: The liquidity pool to delete. Can be the pool id
1850+
as a string, or can be an Asset, asset_id, or symbol of the
1851+
share asset for the pool.
1852+
1853+
"""
1854+
if not account:
1855+
if "default_account" in self.config:
1856+
account = self.config["default_account"]
1857+
if not account:
1858+
raise ValueError("You need to provide an account")
1859+
account = Account(account, blockchain_instance=self)
1860+
1861+
pool_id = self._find_liquidity_pool(pool)
1862+
1863+
op = operations.Liquidity_pool_delete(
1864+
**{
1865+
"fee": {"amount": 0, "asset_id": "1.3.0"},
1866+
"account": account["id"],
1867+
"pool": pool_id,
1868+
"extensions": [],
1869+
}
1870+
)
1871+
return self.finalizeOp(op, account, "active", **kwargs)
1872+
1873+
1874+
def deposit_into_liquidity_pool(self, pool, amount_a, amount_b, account=None, **kwargs):
1875+
"""Deposit assets into a liquidity pool
1876+
1877+
:param str,Asset pool: The liquidity pool to use. Can be the pool id
1878+
as a string, or can be an Asset, asset_id, or symbol of the
1879+
share asset for the pool.
1880+
1881+
:param Amount amount_a:
1882+
:param Amount amount_b:
1883+
1884+
"""
1885+
if not account:
1886+
if "default_account" in self.config:
1887+
account = self.config["default_account"]
1888+
if not account:
1889+
raise ValueError("You need to provide an account")
1890+
account = Account(account, blockchain_instance=self)
1891+
1892+
pool_id = self._find_liquidity_pool(pool)
1893+
1894+
num_id_a = int(amount_a.asset["id"].split(".")[-1])
1895+
num_id_b = int(amount_b.asset["id"].split(".")[-1])
1896+
if(num_id_b < num_id_a):
1897+
amount_a, amount_b = amount_b, amount_a
1898+
1899+
op = operations.Liquidity_pool_deposit(
1900+
**{
1901+
"fee": {"amount": 0, "asset_id": "1.3.0"},
1902+
"account": account["id"],
1903+
"pool": pool_id,
1904+
"amount_a": amount_a.json(),
1905+
"amount_b": amount_b.json(),
1906+
"extensions": [],
1907+
}
1908+
)
1909+
return self.finalizeOp(op, account, "active", **kwargs)
1910+
1911+
1912+
def withdraw_from_liquidity_pool(self, pool, share_amount, account=None, **kwargs):
1913+
"""Withdraw stake from a liquidity pool
1914+
1915+
:param str,Asset pool: The liquidity pool to use. Can be the pool id
1916+
as a string, or can be an Asset, asset_id, or symbol of the
1917+
share asset for the pool.
1918+
1919+
:param Amount share_amount: Amount of share asset to redeem. Must be a
1920+
quantity of the pool's share_asset.
1921+
1922+
"""
1923+
if not account:
1924+
if "default_account" in self.config:
1925+
account = self.config["default_account"]
1926+
if not account:
1927+
raise ValueError("You need to provide an account")
1928+
account = Account(account, blockchain_instance=self)
1929+
1930+
pool_id = self._find_liquidity_pool(pool)
1931+
1932+
op = operations.Liquidity_pool_withdraw(
1933+
**{
1934+
"fee": {"amount": 0, "asset_id": "1.3.0"},
1935+
"account": account["id"],
1936+
"pool": pool_id,
1937+
"share_amount": share_amount.json(),
1938+
"extensions": [],
1939+
}
1940+
)
1941+
return self.finalizeOp(op, account, "active", **kwargs)
1942+
1943+
1944+
def exchange_with_liquidity_pool(self, pool, amount_to_sell, min_to_receive, account=None, **kwargs):
1945+
"""Exchange assets against a liquidity pool
1946+
1947+
:param str,Asset pool: The liquidity pool to use. Can be the pool id
1948+
as a string, or can be an Asset, asset_id, or symbol of the
1949+
share asset for the pool.
1950+
1951+
:param Amount amount_to_sell:
1952+
:param Amount min_to_receive:
1953+
1954+
"""
1955+
if not account:
1956+
if "default_account" in self.config:
1957+
account = self.config["default_account"]
1958+
if not account:
1959+
raise ValueError("You need to provide an account")
1960+
account = Account(account, blockchain_instance=self)
1961+
1962+
pool_id = self._find_liquidity_pool(pool)
1963+
1964+
op = operations.Liquidity_pool_exchange(
1965+
**{
1966+
"fee": {"amount": 0, "asset_id": "1.3.0"},
1967+
"account": account["id"],
1968+
"pool": pool_id,
1969+
"amount_to_sell": amount_to_sell.json(),
1970+
"min_to_receive": min_to_receive.json(),
1971+
"extensions": [],
1972+
}
1973+
)
1974+
return self.finalizeOp(op, account, "active", **kwargs)

bitsharesbase/objecttypes.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@
2020
object_type["htlc"] = 16
2121
object_type["custom_authority"] = 17
2222
object_type["ticket"] = 18
23-
object_type["OBJECT_TYPE_COUNT"] = 18
23+
object_type["liquidity_pool"] = 19
24+
object_type["OBJECT_TYPE_COUNT"] = 19

bitsharesbase/operationids.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@
6060
"custom_authority_delete_operation",
6161
"ticket_create_operation",
6262
"ticket_update_operation",
63+
"liquidity_pool_create",
64+
"liquidity_pool_delete",
65+
"liquidity_pool_deposit",
66+
"liquidity_pool_withdraw",
67+
"liquidity_pool_exchange",
6368
]
6469
operations = {o: ops.index(o) for o in ops}
6570

bitsharesbase/operations.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,4 +1102,113 @@ def __init__(self, *args, **kwargs):
11021102
)
11031103

11041104

1105+
class Liquidity_pool_create(GrapheneObject):
1106+
def __init__(self, *args, **kwargs):
1107+
if isArgsThisClass(self, args):
1108+
self.data = args[0].data
1109+
else:
1110+
if len(args) == 1 and len(kwargs) == 0:
1111+
kwargs = args[0]
1112+
1113+
super().__init__(
1114+
OrderedDict(
1115+
[
1116+
("fee", Asset(kwargs["fee"])),
1117+
("account", ObjectId(kwargs["account"], "account")),
1118+
("asset_a", ObjectId(kwargs["asset_a"], "asset")),
1119+
("asset_b", ObjectId(kwargs["asset_b"], "asset")),
1120+
("share_asset", ObjectId(kwargs["share_asset"], "asset")),
1121+
("taker_fee_percent", Uint16(kwargs["taker_fee_percent"])),
1122+
("withdrawal_fee_percent", Uint16(kwargs["withdrawal_fee_percent"])),
1123+
("extensions", Set([])),
1124+
]
1125+
)
1126+
)
1127+
1128+
1129+
class Liquidity_pool_delete(GrapheneObject):
1130+
def __init__(self, *args, **kwargs):
1131+
if isArgsThisClass(self, args):
1132+
self.data = args[0].data
1133+
else:
1134+
if len(args) == 1 and len(kwargs) == 0:
1135+
kwargs = args[0]
1136+
1137+
super().__init__(
1138+
OrderedDict(
1139+
[
1140+
("fee", Asset(kwargs["fee"])),
1141+
("account", ObjectId(kwargs["account"], "account")),
1142+
("pool", ObjectId(kwargs["pool"], "liquidity_pool")),
1143+
("extensions", Set([])),
1144+
]
1145+
)
1146+
)
1147+
1148+
1149+
class Liquidity_pool_deposit(GrapheneObject):
1150+
def __init__(self, *args, **kwargs):
1151+
if isArgsThisClass(self, args):
1152+
self.data = args[0].data
1153+
else:
1154+
if len(args) == 1 and len(kwargs) == 0:
1155+
kwargs = args[0]
1156+
1157+
super().__init__(
1158+
OrderedDict(
1159+
[
1160+
("fee", Asset(kwargs["fee"])),
1161+
("account", ObjectId(kwargs["account"], "account")),
1162+
("pool", ObjectId(kwargs["pool"], "liquidity_pool")),
1163+
("amount_a", Asset(kwargs["amount_a"])),
1164+
("amount_b", Asset(kwargs["amount_b"])),
1165+
("extensions", Set([])),
1166+
]
1167+
)
1168+
)
1169+
1170+
1171+
class Liquidity_pool_withdraw(GrapheneObject):
1172+
def __init__(self, *args, **kwargs):
1173+
if isArgsThisClass(self, args):
1174+
self.data = args[0].data
1175+
else:
1176+
if len(args) == 1 and len(kwargs) == 0:
1177+
kwargs = args[0]
1178+
1179+
super().__init__(
1180+
OrderedDict(
1181+
[
1182+
("fee", Asset(kwargs["fee"])),
1183+
("account", ObjectId(kwargs["account"], "account")),
1184+
("pool", ObjectId(kwargs["pool"], "liquidity_pool")),
1185+
("share_amount", Asset(kwargs["share_amount"])),
1186+
("extensions", Set([])),
1187+
]
1188+
)
1189+
)
1190+
1191+
1192+
class Liquidity_pool_exchange(GrapheneObject):
1193+
def __init__(self, *args, **kwargs):
1194+
if isArgsThisClass(self, args):
1195+
self.data = args[0].data
1196+
else:
1197+
if len(args) == 1 and len(kwargs) == 0:
1198+
kwargs = args[0]
1199+
1200+
super().__init__(
1201+
OrderedDict(
1202+
[
1203+
("fee", Asset(kwargs["fee"])),
1204+
("account", ObjectId(kwargs["account"], "account")),
1205+
("pool", ObjectId(kwargs["pool"], "liquidity_pool")),
1206+
("amount_to_sell", Asset(kwargs["amount_to_sell"])),
1207+
("min_to_receive", Asset(kwargs["min_to_receive"])),
1208+
("extensions", Set([])),
1209+
]
1210+
)
1211+
)
1212+
1213+
11051214
fill_classmaps()

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
ascii = codecs.lookup("ascii")
1414
codecs.register(lambda name, enc=ascii: {True: enc}.get(name == "mbcs"))
1515

16-
__version__ = "0.6.0"
16+
__version__ = "0.7.0"
1717
URL = "https://github.com/bitshares/python-bitshares"
1818

1919
setup(

0 commit comments

Comments
 (0)