Python SDK overview

The SDK source code can be found on Github

Install SDK

In your terminal run:

pip install qb-sdk

Instantiate the SDK object

api_key = 'your_secret_api_key'
token_symbol = 'your_token_symbol'
mode = qbsdk.Mode.sandbox
api = qbsdk.Api(api_key, mode)

Retrieve all tokens

tokens = api.get_tokens()
for token in tokens.private:
    print(vars(token))

Setup the brand wallet and send a transaction

brand_address_private_key = 'your_brand_address_private_key'

wallet = qbsdk.Wallet(brand_address_private_key, token_symbol, api, transfer_strategy=qbsdk.TransferStrategy.brand)

# setup method is required before starting to send transactions
wallet.setup()

transfer_receiver = '0x87265a62c60247f862b9149423061b36b460f4bb'
tx = wallet.send_transaction(transfer_receiver, 10)

Creating brand wallets

For creating an Ethereum wallet that will hold your brand tokens you can use a mainstream solution such as www.myetherwallet.com or metamask

For more security you can consider using a hardware wallet, as long as you're able to access the private key for your address and configure your server code to use it when using the SDK.

Creating user wallets

For creating user wallets you can use the SDK functionality as such:

# Create a random custodial wallet on the server-side
random_uninitialized_wallet = qbsdk.Wallet.create_random(None, None)

# Create wallet from an existing private key with defined symbol and api to be able to send
other_user = qbsdk.Wallet(other_user_private_key, token_symbol, api, qbsdk.TransferStrategy.user)

Transaction transfer strategy

The Wallet object supports 2 strategies for sending transactions: brand and user. This is because user wallets and brand wallets have different requirements when it comes to transaction throughputs: brands need to reward potentially multiple times per second, while a user sends transactions once in a while.

Currently, to achieve the highest possible throughput for brand transactions, send them sequentially as shown here, to give the blockchain the opportunity to assign the correct order number (nonce) to each transaction:

from gevent import monkey
monkey.patch_all()
import qbsdk
import time
import threading
import os

TOTAL_TX_COUNT = 10
POLLING_INTERVAL_MS = 200

api = qbsdk.Api(api_key)

wallet = qbsdk.Wallet(brand_address_private_key, token_symbol, api, qbsdk.TransferStrategy.brand)
wallet.setup()

def wait_for_tx_completion(tx):
    print(f'Checking for tx {tx.hash}')
    while True:
        try:
            processed_tx = api.get_transaction(tx.hash)
            if processed_tx.confirms >= 1:
                # consider tx completed.
                break
            sleep_time = POLLING_INTERVAL_MS / 1000
            time.sleep(sleep_time)
        except qbsdk.error.NotFoundError as e:
            # Tx has not been processed yet.
            sleep_time = POLLING_INTERVAL_MS / 1000
            print(f'Sleeping for {sleep_time}')
            time.sleep(sleep_time)
        except Exception as e:
            print(f'ERROR: {e}')
            # some other error occured. Retry your transaction.
    print(f'Transaction with hash {processed_tx.hash}')

for i in range(0, TOTAL_TX_COUNT):
    print(f'Sending tx {i}')
    i += 1
    start_millis =  int(round(time.time() * 1000))
    try:
        pending_tx = wallet.send_transaction(transfer_receiver, i)
    except Exception as e:
        print(f'Failed with {e}')
        continue
    thread = threading.Thread(target=wait_for_tx_completion, args=(pending_tx,))
    thread.start()
print('finished.')

Note that this checks for transaction completion asynchronously in another thread. To optimize the I/O operations, this code uses gevent which transforms the Python Thread into a Greenlet lightweight thread.

Since all blockchain transactions are asynchronous one needs to check for completion. Until webhooks are implemented, the supported way of detecting completion is polling.

If you require a higher throughput than what this implementation provides, contact us and we can discuss the use-case and provide you support on how to solve it.

For advanced users: nonce management

If you are comfortable with the Ethereum transaction nonce concept, you can have finer tuned control here and implement your own nonce management strategy to achieve higher throughputs. The SDK allows you to override it as such:

pending_tx = wallet.send_transaction(transfer_receiver, transfer_value, nonce_override)

This way the nonce management is all on you and the SDK nonce management strategy is disabled.

The next SDK release is planned to support sending of batched transactions that will enable 1 order of magnitude higher throughput per address.