Welcome to steempy’s documentation!¶
Steem is a blockchain-based autonomous company (i.e. a DAC) that offers decentralized exchanging as well as sophisticated financial instruments as products.
It is based on Graphene (tm), a blockchain technology stack (i.e. software) that allows for fast transactions and ascalable blockchain solution. In case of Steem, it comes with decentralized trading of assets as well as customized on-chain smart contracts.
About this Library¶
The purpose of steempy is to simplify development of products and services that use the Steem blockchain. It comes with
- it’s own (bip32-encrypted) wallet
- RPC interface for the Blockchain backend
- JSON-based blockchain objects (accounts, blocks, prices, markets, etc)
- a simple to use yet powerful API
- transaction construction and signing
- push notification API
- and more
Quickstart¶
Note
- All methods that construct and sign a transaction can be given
the
account=
parameter to identify the user that is going to affected by this transaction, e.g.:- the source account in a transfer
- the accout that buys/sells an asset in the exchange
- the account whos collateral will be modified
Important, If no account
is given, then the
default_account
according to the settings in config
is
used instead.
from steempy import Steem
steem = Steem()
steem.wallet.unlock("wallet-passphrase")
steem.transfer("<to>", "<amount>", "<asset>", "<memo>", account="<from>")
from steempy.blockchain import Blockchain
blockchain = Blockchain()
for op in Blockchain.ops():
print(op)
from steempy.block import Block
print(Block(1))
from steempy.account import Account
account = Account("test")
print(account.balances)
print(account.openorders)
for h in account.history():
print(h)
from steempy.market import Market
# Not working at the moment
# market = Market("STEEM:SBD")
# print(market.ticker())
# market.steem.wallet.unlock("wallet-passphrase")
# print(market.sell(300, 100) # sell 100 STEEM for 300 STEEM/SBD
from steempy.dex import Dex
# not working at the moment
# dex = Dex()
# dex.steem.wallet.unlock("wallet-passphrase")
General¶
Installation¶
Installation¶
Install with pip:
$ sudo apt-get install libffi-dev libssl-dev python-dev
$ pip3 install steempy
Manual installation:
$ git clone https://github.com/holgern/steempy/
$ cd steempy
$ python3 setup.py install --user
Upgrade¶
$ pip install --user --upgrade
Quickstart¶
Tutorials¶
Bundle Many Operations¶
With Steem, you can bundle multiple operations into a single transactions. This can be used to do a multi-send (one sender, multiple receivers), but it also allows to use any other kind of operation. The advantage here is that the user can be sure that the operations are executed in the same order as they are added to the transaction.
from pprint import pprint
from steempy import Steem
testnet = Steem(
"wss://testnet.steem.vc",
nobroadcast=True,
bundle=True,
)
testnet.wallet.unlock("supersecret")
testnet.transfer("test1", 1, "STEEM", account="test")
testnet.transfer("test1", 1, "STEEM", account="test")
testnet.transfer("test1", 1, "STEEM", account="test")
testnet.transfer("test1", 1, "STEEM", account="test")
pprint(testnet.broadcast())
Proposing a Transaction¶
In Steem, you can propose a transactions to any account. This is
used to facilitate on-chain multisig transactions. With
python-steem, you can do this simply by using the proposer
attribute:
from pprint import pprint
from steempy import Steem
testnet = Steem(
"wss://testnet.steem.vc",
proposer="test"
)
testnet.wallet.unlock("supersecret")
pprint(testnet.transfer("tst1", 1, "STEEM", account="test"))
Simple Sell Script¶
from steempy import Steem
from steempy.market import Market
from steempy.price import Price
from steempy.amount import Amount
#
# Instanciate Steem (pick network via API node)
#
steem = Steem(
"wss://node.testnet.steem.eu",
nobroadcast=True # <<--- set this to False when you want to fire!
)
#
# Unlock the Wallet
#
steem.wallet.unlock("<supersecret>")
#
# This defines the market we are looking at.
# The first asset in the first argument is the *quote*
# Sell and buy calls always refer to the *quote*
#
market = Market(
"GOLD:USD",
steem_instance=steem
)
#
# Sell an asset for a price with amount (quote)
#
print(market.sell(
Price(100.0, "USD/GOLD"),
Amount("0.01 GOLD")
))
Sell at a timely rate¶
import threading
from steempy import Steem
from steempy.market import Market
from steempy.price import Price
from steempy.amount import Amount
def sell():
""" Sell an asset for a price with amount (quote)
"""
print(market.sell(
Price(100.0, "USD/GOLD"),
Amount("0.01 GOLD")
))
threading.Timer(60, sell).start()
if __name__ == "__main__":
#
# Instanciate Steem (pick network via API node)
#
steem = Steem(
"wss://node.testnet.steem.eu",
nobroadcast=True # <<--- set this to False when you want to fire!
)
#
# Unlock the Wallet
#
steem.wallet.unlock("<supersecret>")
#
# This defines the market we are looking at.
# The first asset in the first argument is the *quote*
# Sell and buy calls always refer to the *quote*
#
market = Market(
"GOLD:USD",
steem_instance=steem
)
sell()
Configuration¶
The pysteem library comes with its own local configuration database that stores information like
- API node URL
- default account name
- the encrypted master password
and potentially more.
You can access those variables like a regular dictionary by using
from steempy import Steem
steem = Steem()
print(steem.config.items())
Keys can be added and changed like they are for regular dictionaries.
If you don’t want to load the steem.Steem
class, you
can load the configuration directly by using:
from steempy.storage import configStorage as config
API¶
Contributing to python-steem¶
We welcome your contributions to our project.
Flow¶
This project makes heavy use of git flow. If you are not familiar with it, then the most important thing for your to understand is that:
pull requests need to be made against the develop branch
How to Contribute¶
- Familiarize yourself with contributing on github <https://guides.github.com/activities/contributing-to-open-source/>
- Fork or branch from the master.
- Create commits following the commit style
- Start a pull request to the master branch
- Wait for a @holger80 or another member to review
Issues¶
Feel free to submit issues and enhancement requests.
Contributing¶
Please refer to each project’s style guidelines and guidelines for submitting patches and additions. In general, we follow the “fork-and-pull” Git workflow.
- Fork the repo on GitHub
- Clone the project to your own machine
- Commit changes to your own branch
- Push your work back up to your fork
- Submit a Pull request so that we can review your changes
NOTE: Be sure to merge the latest from “upstream” before making a pull request!
Copyright and Licensing¶
This library is open sources under the MIT license. We require your to release your code under that license as well.
Support and Questions¶
We have currently not setup a distinct channel for development around pysteemi. However, many of the contributors are frequently reading through these channels:
steempy Libraries¶
Steem¶
The Steem library has been designed to allow developers to easily access its routines and make use of the network without dealing with all the related blockchain technology and cryptography. This library can be used to do anything that is allowed according to the Steem blockchain protocol.
Instances¶
Default instance to be used when no steem_instance
is given to
the Objects!
from steempy.instance import shared_steem_instance
account = Account("test")
# is equivalent with
account = Account("test", steem_instance=shared_steem_instance())
Account¶
Obtaining data of an account.
from steempy.account import Account
account = Account("test")
print(account)
print(account.balances)
Amount¶
For the sake of easier handling of Assets on the blockchain
from steempy.amount import Amount
from steempy.asset import Asset
a = Amount("1 USD")
b = Amount(1, "USD")
c = Amount("20", Asset("USD"))
a + b
a * 2
a += b
a /= 2.0
Asset¶
Block¶
Easily read data in a Block
from steempy.block import Block
from pprint import pprint
pprint(Block(1))
Blockchain¶
Read blockchain related data-
from steempy.blockchain import Blockchain
chain = Blockchain()
Read current block and blockchain info
print(chain.get_current_block())
print(chain.info())
Monitor for new blocks ..
for block in chain.blocks():
print(block)
… or each operation individually:
for operations in chain.ops():
print(operations)
Exceptions¶
Market¶
Notify¶
This modules allows yout to be notified of events taking place on the blockchain.
Price¶
Low Level Classes¶
Utilities¶
Transaction Builder¶
To build your own transactions and sign them
from steempy.transactionbuilder import TransactionBuilder
from steempybase.operations import Transfer
tx = TransactionBuilder()
tx.appendOps(Transfer(**{
"from": "test",
"to": "test1",
"amount": "1 STEEM",
"memo": ""
}))
tx.appendSigner("test", "active")
tx.sign()
tx.broadcast()
Wallet¶
Create a new wallet¶
A new wallet can be created by using:
from steempy import Steem
steem = Steem()
steem.wallet.create("supersecret-passphrase")
This will raise an exception if you already have a wallet installed.
Unlocking the wallet for signing¶
The wallet can be unlocked for signing using
from steempy import Steem
steem = Steem()
steem.wallet.unlock("supersecret-passphrase")
Adding a Private Key¶
A private key can be added by using the
steem.wallet.Wallet.addPrivateKey()
method that is available
after unlocking the wallet with the correct passphrase:
from steempy import Steem
steem = Steem()
steem.wallet.unlock("supersecret-passphrase")
steem.wallet.addPrivateKey("5xxxxxxxxxxxxxxxxxxxx")
Note
The private key has to be either in hexadecimal or in wallet
import format (wif) (starting with a 5
).
API¶
SteemWebsocket¶
This class allows subscribe to push notifications from the Steem node.
from pprint import pprint
from steempyapi.websocket import SteemWebsocket
ws = SteemWebsocket(
"wss://gtg.steem.house:8090",
accounts=["test"],
# on_market=pprint,
# on_block=print,
on_account=print,
)
ws.run_forever()
Defintion¶
SteemNodeRPC¶
This class allows to call API methods exposed by the witness node via websockets.
Defintion¶
Manual Constructing and Signing of Transactions¶
Warning
This is a low level class. Do not use this class unless you know what you are doing!
Note
This class is under development and meant for people that are looking into the low level construction and signing of various transactions.
Loading Transactions Class¶
We load the class for manual transaction construction via:
from steempybase import transactions, operations
Construction¶
Now we can use the predefined transaction formats, e.g. Transfer
or
limit_order_create
as follows:
- define the expiration time
- define a JSON object that contains all data for that transaction
- load that data into the corresponding operations class
- collect multiple operations
- get some blockchain parameters to prevent replay attack
- Construct the actual transaction from the list of operations
- sign the transaction with the corresponding private key(s)
Example A: Transfer
expiration = transactions.formatTimeFromNow(60)
op = operations.Transfer(**{
"from": "test",
"to": "test1",
"amount": "1.000 SBD",
"memo": ""
})
ops = [transactions.Operation(op)]
ref_block_num, ref_block_prefix = transactions.getBlockParams(rpc)
tx = transactions.Signed_Transaction(ref_block_num=ref_block_num,
ref_block_prefix=ref_block_prefix,
expiration=expiration,
operations=ops)
tx = tx.sign([wif])
Broadcasting¶
For broadcasting, we first need to convert the transactions class into a JSON object. After that, we can broadcast this to the network:
# Broadcast JSON to network
rpc.broadcast_transaction(tx.json(), api="network_broadcast"):
Memo¶
Memo Keys¶
In BitShares, memos are AES-256 encrypted with a shared secret between sender and receiver. It is derived from the memo private key of the sender and the memo publick key of the receiver.
In order for the receiver to decode the memo, the shared secret has to be derived from the receiver’s private key and the senders public key.
The memo public key is part of the account and can be retreived with the get_account call:
get_account <accountname>
{
[...]
"options": {
"memo_key": "GPH5TPTziKkLexhVKsQKtSpo4bAv5RnB8oXcG4sMHEwCcTf3r7dqE",
[...]
},
[...]
}
while the memo private key can be dumped with dump_private_keys
Memo Message¶
The take the following form:
{
"from": "GPH5mgup8evDqMnT86L7scVebRYDC2fwAWmygPEUL43LjstQegYCC",
"to": "GPH5Ar4j53kFWuEZQ9XhxbAja4YXMPJ2EnUg5QcrdeMFYUNMMNJbe",
"nonce": "13043867485137706821",
"message": "d55524c37320920844ca83bb20c8d008"
}
The fields from and to contain the memo public key of sender and receiver. The nonce is a random integer that is used for the seed of the AES encryption of the message.
Example¶
Encrypting a memo¶
The high level memo class makes use of the pysteem wallet to obtain keys for the corresponding accounts.
from steempy.memo import Memo
from steempy.account import Account
memoObj = Memo(
from_account=Account(from_account),
to_account=Account(to_account)
)
encrypted_memo = memoObj.encrypt(memo)
Decoding of a received memo¶
from getpass import getpass
from steempy.block import Block
from steempy.memo import Memo
# Obtain a transfer from the blockchain
block = Block(23755086) # block
transaction = block["transactions"][3] # transactions
op = transaction["operations"][0] # operation
op_id = op[0] # operation type
op_data = op[1] # operation payload
# Instantiate Memo for decoding
memo = Memo()
# Unlock wallet
memo.unlock_wallet(getpass())
# Decode memo
# Raises exception if required keys not available in the wallet
print(memo.decrypt(op_data["memo"]))