def appendTransferOpToTx(builder, from_name, to_name, amount, symbol): ## TODO: Cleanup exception catching for better user feedback try: account = Account(from_name, blockchain_instance=blockchain) amountAsset = Amount(amount, symbol, blockchain_instance=blockchain) to = Account(to_name, blockchain_instance=blockchain) except NumRetriesReached: Logger.Write("ERROR: Can't reach API node: 'NumRetries' reached. Check network connection.") raise except: Logger.Write("Problem locating source or destination account, or asset. Might not exist.") raise memoObj = Memo(from_account=account, to_account=to, blockchain_instance=blockchain) memo_text = "" #"Signed by BitShares App on Ledger Nano S!" op = operations.Transfer( **{ "fee": {"amount": 0, "asset_id": "1.3.0"}, "from": account["id"], "to": to["id"], "amount": {"amount": int(amountAsset), "asset_id": amountAsset.asset["id"]}, "memo": memoObj.encrypt(memo_text), } ) builder.appendOps(op) return builder
def append_transfer_tx(append_to, dest_account_name): # # `append_to` is a TransactionBuilder object. (E.g. from BitShares.new_tx()) # `dest_account_name` is a string account name. # account = Account(tip_sender, blockchain_instance=blockchain) amount = Amount(tip_amount, tip_asset_symbol, blockchain_instance=blockchain) try: to = Account(dest_account_name, blockchain_instance=blockchain) except NumRetriesReached: Logger.Write( "ERROR: Can't reach API node: 'NumRetries' reached. Check network connection." ) raise except: Logger.Write("Problem locating destination account. Might not exist.") raise memoObj = Memo(from_account=account, to_account=to, blockchain_instance=blockchain) memo_text = "" #"Signed by BitShares App on Ledger Nano S!" op = operations.Transfer( **{ "fee": { "amount": 0, "asset_id": "1.3.0" }, "from": account["id"], "to": to["id"], "amount": { "amount": int(amount), "asset_id": amount.asset["id"] }, "memo": memoObj.encrypt(memo_text), }) append_to.appendOps(op) return append_to
def getMemo(self, from_account, to_account, text=None, data=None): if (data): from_account = data["from"] to_account = data["to"] #data = data["message"] #import traceback #try: # from_account = self.getAccount(from_account) #except: # traceback.print_exc() # #print(from_account # #print(from_account) try: to_account = self.getAccount(to_account) to_account_name = to_account["name"] except: to_account_name = to_account to_account = None #invert = True #to_account = self.getAccount(to_account) try: from_account = self.getAccount(from_account) from_account_name = from_account["name"] except: from_account_name = from_account from_account = None #print("TO:", to_account) #print("FROM:", from_account) #if (self.isCachedAccount(to_account['name'])): # invert = False #else: # if not(from_account): # showerror(from_account_name) # return False from bitshares.memo import Memo memoObj = Memo( from_account=None, #from_account, to_account=None, #to_account, bitshares_instance=self.bts) memoObj.chain_prefix = self.chain_prefix() memoObj.from_account = from_account memoObj.to_account = to_account if text: # { nonce, to from, message } json: return memoObj.encrypt(text) # plaintext: return { 'message': memoObj.decrypt(data), 'from': from_account_name, #from_account['name'] 'to': to_account_name, #to_account['name'], }
def play_game(account, amountBet, userRoll): memo = Memo('bts-dice-game', account) nodeForConnections = 'wss://api.bitsharesdex.com' blockchain = Blockchain(node=nodeForConnections, mode='head') bitshares = BitShares( node=nodeForConnections, nobroadcast=False, ) blockNum = blockchain.get_current_block_num() userGuess = userRoll seed(blockNum * (userGuess + 1)) diceRatios = btsDiceRatios winRatio = diceRatios.get_ratio(userGuess) value = randint(1, 100) correctGuess = value < int(userGuess) bitshares.wallet.unlock('superSecretPassword') if winRatio is None: print('You submitted something not correct to this contract.') elif correctGuess: winningAmount = winRatio * amountBet winningString = "Correct! You guessed {0} and rolled {1}. You won {2:.5f} BTS.".format( userRoll, value, winningAmount) bitshares.transfer(account, winningAmount, 'BTS', winningString, account='bts-dice-game') print(winningString) else: losingString = "Incorrect. You guessed {0} and rolled {1}.".format( userRoll, value) bitshares.transfer(account, 0.00001, 'BTS', losingString, account='bts-dice-game') print( 'You guessed incorrectly. Your guess was {a} and you rolled {b}.'. format(a=userRoll, b=value))
def decode_memo(self, payload): """ This method decodes the memo for us. .. note:: Three cases exist that prevent us from decoding a memo that lead to a special message being used instead: * ``memo_key_missing``: In the case the decryption key was not provided * ````: In the case no memo was provided * ``decoding_not_possible``: In the case, the memo couldn't be decrypted """ try: decoded_memo = Memo( bitshares_instance=self.bitshares ).decrypt(payload["memo"]) except MissingKeyError: decoded_memo = "memo_key_missing" except KeyError: decoded_memo = "" except ValueError: decoded_memo = "decoding_not_possible" return decoded_memo
def pprintOperation(op, show_memo=False, ctx=None): from bitshares.price import Order, FilledOrder if isinstance(op, dict) and "op" in op: id = op["op"][0] op = op["op"][1] else: id = op[0] op = op[1] if id == 1: return str(Order(op)) elif id == 4: return str(FilledOrder(op)) elif id == 5: return "New account created for {}".format(op["name"]) elif id == 2: return "Canceled order %s" % op["order"] elif id == 6: return "Account {} updated".format(Account(op["account"])["name"]) elif id == 33: return "Claiming from vesting: %s" % str(Amount(op["amount"])) elif id == 15: return "Reserve {}".format(str(Amount(op["amount_to_reserve"]))) elif id == 0: from_account = Account(op["from"]) to_account = Account(op["to"]) amount = Amount(op["amount"]) memo = "" if show_memo and ctx is not None: try: plain_memo = Memo(blockchain_instance=ctx.blockchain).decrypt( op["memo"]) except Exception as e: plain_memo = str(e) memo = " (memo: {plain_memo})".format(**locals()) return "Transfer from {from_account[name]} to {to_account[name]}: {amount}{memo}".format( **locals()) else: return format_dict(op)
logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) NODE_URL = os.getenv('BITSHARES_NODE_URL', 'wss://node.testnet.bitshares.eu') GATEWAY_ACCOUNT_ID = os.getenv('GATEWAY_ACCOUNT', '1.2.3604') GATEWAY_ACCOUNT_WIF = '5KiQYz2MBTWH676biQcVwx6zJ1J3cYb65bZThRBav1z7gU2MoMu' START_BLOCK = os.getenv('START_BLOCK', cache.get('START_BLOCK')) if START_BLOCK: START_BLOCK = int(START_BLOCK) bitshares = BitShares(node=NODE_URL, keys=[GATEWAY_ACCOUNT_WIF]) set_shared_blockchain_instance(bitshares) m = Memo() logger.info('Gateway running..') logger.info(f'START_BLOCK: {START_BLOCK}') logger.info(f'NODE_URL: {NODE_URL}') logger.info(f'GATEWAY_ACCOUNT_ID: {GATEWAY_ACCOUNT_ID}') logger.info(f'GATEWAY_ACCOUNT_WIF: {GATEWAY_ACCOUNT_WIF[:5]}..') logger.info(f'EOS_NODE_URL: {eosio_config.url}') logger.info(f'EOS_NODE_PORT: {eosio_config.port}') logger.info(f'ISSUER_WIF: {ISSUER_WIF}') logger.info(f'ISSUER_NAME: {ISSUER_NAME}') logger.info(f'ISSUE_ASSET: {ISSUE_ASSET}') def parse_transfer(op): # TODO Разобраться где обрабатывать пресижн
def send(self, amount, address, memo=None, from_address=None) -> dict: """ Send tokens to a given address/account, optionally specifying a memo. The Bitshares network transaction fee will be subtracted from the amount before sending. There must be a valid :py:class:`models.CryptoKeyPair` in the database for both 'active' and 'memo' keys for the from_address account, or an AuthorityMissing exception will be thrown. Example - send 1.23 BUILDTEAM from @someguy123 to @privex with memo 'hello' >>> s = BitsharesManager('BUILDTEAM') >>> s.send(from_address='someguy123', address='privex', amount=Decimal('1.23'), memo='hello') :param Decimal amount: Amount of tokens to send, as a Decimal() :param address: Account to send the tokens to :param from_address: Account to send the tokens from :param memo: Memo to send tokens with :raises AttributeError: When both `from_address` and `self.coin.our_account` are blank. :raises ArithmeticError: When the amount is lower than the lowest amount allowed by the token's precision (after subtracting the network transaction fee) :raises AuthorityMissing: Cannot send because we don't have authority to (missing key etc.) :raises AccountNotFound: The requested account/address doesn't exist :raises TokenNotFound: When the requested token `symbol` does not exist :raises NotEnoughBalance: The account `from_address` does not have enough balance to send this amount. :return dict: Result Information Format:: { txid:str - Transaction ID - None if not known, coin:str - Symbol that was sent, amount:Decimal - The amount that was sent (after fees), fee:Decimal - TX Fee that was taken from the amount, from:str - The account/address the coins were sent from, send_type:str - Should be statically set to "send" } """ # Try from_address first. If that's empty, try using self.coin.our_account. If both are empty, abort. if empty(from_address): if empty(self.coin.our_account): raise AttributeError( "Both 'from_address' and 'coin.our_account' are empty. Cannot send." ) from_address = self.coin.our_account # make sure we have the necessary private keys loaded (memo key for encrypting memo, active key for sending coins) self.set_wallet_keys(from_address, ['memo', 'active']) asset_obj = self.get_asset_obj(self.symbol) if asset_obj is None: raise exceptions.TokenNotFound( f'Failed to send because {self.symbol} is an invalid token symbol.' ) # trim input amount to the token's precision just to be safe str_amount = ('{0:.' + str(asset_obj['precision']) + 'f}').format(amount) amount = Decimal(str_amount) if not self.is_amount_above_minimum(amount, asset_obj['precision']): raise ArithmeticError( f'Failed to send because {amount} is less than the minimum amount allowed for {self.symbol} tokens.' ) from_account = self.get_account_obj(from_address) if from_account is None: raise exceptions.AccountNotFound( f'Failed to send because source account {from_address} could not be found.' ) to_account = self.get_account_obj(address) if to_account is None: raise exceptions.AccountNotFound( f'Failed to send because destination account {address} could not be found.' ) # verify from_account balance is sufficient for the transaction from_account_balance = self.get_decimal_from_amount( from_account.balance(self.symbol)) if from_account_balance < amount: raise exceptions.NotEnoughBalance( f'Failed to send because source account {from_address} balance {from_account_balance} {self.symbol} is less than amount to send ({amount} {self.symbol}).' ) amount_obj = Amount(str_amount, self.symbol, blockchain_instance=self.bitshares) try: if memo is None: memo = '' memo_obj = Memo(from_account=from_account, to_account=to_account, blockchain_instance=self.bitshares) encrypted_memo = memo_obj.encrypt(memo) # build preliminary transaction object, without network transaction fee op = operations.Transfer( **{ 'fee': { 'amount': 0, 'asset_id': amount_obj.asset['id'] }, 'from': from_account['id'], 'to': to_account['id'], 'amount': { 'amount': int(amount_obj), 'asset_id': amount_obj.asset['id'] }, 'memo': encrypted_memo, 'prefix': self.bitshares.prefix, }) # calculate how much the transaction fee is - rather clunky method here but it works ops = [self.bitshares.txbuffer.operation_class(op)] ops_with_fees = self.bitshares.txbuffer.add_required_fees( ops, asset_id=amount_obj.asset['id']) raw_fee_amount = Decimal( str(ops_with_fees[0][1].data['fee']['amount'])) fee_amount_str = '{0:f}'.format( raw_fee_amount / (10**amount_obj.asset['precision'])) fee_amount = Amount(fee_amount_str, self.symbol, blockchain_instance=self.bitshares) amount_obj = amount_obj - fee_amount # verify the amount still makes sense after subtracting the transaction fee if int(amount_obj) < 1: raise ArithmeticError( f'Failed to send because {amount} is less than the network transaction fee of {fee_amount_str} {self.symbol} tokens.' ) # correct the transaction object to take into account the transaction fee adj_op = operations.Transfer( **{ 'fee': { 'amount': int(fee_amount), 'asset_id': amount_obj.asset['id'] }, 'from': from_account['id'], 'to': to_account['id'], 'amount': { 'amount': int(amount_obj), 'asset_id': amount_obj.asset['id'] }, 'memo': encrypted_memo, 'prefix': self.bitshares.prefix, }) log.debug( 'doing Bitshares transaction - from_address[%s], address[%s], amount[%s %s], fee_amount[%s], amount_obj[%s], memo[%s]', from_address, address, str_amount, self.symbol, fee_amount, amount_obj, memo) # and finally, do the op! self.bitshares.finalizeOp(adj_op, from_address, "active", fee_asset=amount_obj.asset['id']) result = self.bitshares.broadcast() except KeyNotFound as e: raise exceptions.AuthorityMissing(str(e)) return { 'txid': None, # transaction ID is not readily available from the Bitshares API 'coin': self.orig_symbol, 'amount': self.get_decimal_from_amount(amount_obj), 'fee': self.get_decimal_from_amount(fee_amount), 'from': from_address, 'send_type': 'send' }
from bitshares.memo import Memo from bitshares.instance import set_shared_blockchain_instance from raven.contrib.django.raven_compat.models import client # TODO Сентри # FIXME # GATEWAY_ACCOUNT = os.getenv('GATEWAY_ACCOUNT') NODE_URL = os.getenv('BITSHARES_NODE_URL', 'wss://node.testnet.bitshares.eu') GATEWAY_ACCOUNT_ID = os.getenv('GATEWAY_ACCOUNT', '1.2.3604') GATEWAY_ACCOUNT_WIF = '5KiQYz2MBTWH676biQcVwx6zJ1J3cYb65bZThRBav1z7gU2MoMu' bitshares = BitShares(node=NODE_URL, keys=[GATEWAY_ACCOUNT_WIF]) set_shared_blockchain_instance(bitshares) m = Memo() logging.basicConfig( level=logging.WARN, format="%(asctime)s [%(threadName)s] [%(levelname)s] %(message)s", handlers=[ # logging.FileHandler("{0}/{1}.log".format(logPath, fileName)), logging.StreamHandler() ]) logger.info(f'Gateway running..') logger.info(f'NODE_URL: {NODE_URL}') logger.info(f'GATEWAY_ACCOUNT_ID: {GATEWAY_ACCOUNT_ID}') logger.info(f'GATEWAY_ACCOUNT_WIF: {GATEWAY_ACCOUNT_WIF[:5]}..') logger.info(f'EOS_NODE_URL: {eosio_config.url}') logger.info(f'EOS_NODE_PORT: {eosio_config.port}')
def issue(self, amount: Decimal, address: str, memo: str = None, trigger_data=None) -> dict: """ Issue (create/print) tokens to a given address/account, optionally specifying a memo if desired. The network transaction fee for issuance will be paid by the issuing account in BTS. Example - Issue 5.10 SGTK to @privex >>> s = BitsharesManager('SGTK') >>> s.issue(address='privex', amount=Decimal('5.10')) :param Decimal amount: Amount of tokens to issue, as a Decimal :param address: Account to issue the tokens to (which is also the issuer account) :param memo: Optional memo for the issuance transaction :raises IssuerKeyError: Cannot issue because we don't have authority to (missing key etc.) :raises TokenNotFound: When the requested token `symbol` does not exist :raises AccountNotFound: The requested account doesn't exist :raises ArithmeticError: When the amount is lower than the lowest amount allowed by the token's precision :return dict: Result Information Format:: { txid:str - Transaction ID - None if not known, coin:str - Symbol that was sent, amount:Decimal - The amount that was issued, fee:Decimal - TX Fee that was taken from the amount (will be 0 if fee is in BTS rather than the issuing token), from:str - The account/address the coins were issued from, send_type:str - Should be statically set to "issue" } """ asset_obj = self.get_asset_obj(self.symbol) if asset_obj is None: raise exceptions.TokenNotFound(f'Failed to issue because {self.symbol} is an invalid token symbol.') # trim input amount to the token's precision just to be safe str_amount = ('{0:.' + str(asset_obj['precision']) + 'f}').format(amount) amount = Decimal(str_amount) if not self.is_amount_above_minimum(amount, asset_obj['precision']): raise ArithmeticError(f'Failed to issue because {amount} is less than the minimum amount allowed for {self.symbol} tokens.') to_account = self.get_account_obj(address) if to_account is None: raise exceptions.AccountNotFound(f'Failed to issue because issuing account {address} could not be found.') amount_obj = Amount(str_amount, self.symbol, blockchain_instance=self.bitshares) try: # make sure we have the necessary private keys loaded (memo key for encrypting memo, active key for issuing coins) self.set_wallet_keys(address, [ 'memo', 'active' ]) if memo is None: memo = '' memo_obj = Memo(from_account=to_account, to_account=to_account, blockchain_instance=self.bitshares) encrypted_memo = memo_obj.encrypt(memo) # construct the transaction - note that transaction fee for issuance will be paid in BTS, but we retain the # flexibility to add support for paying the fee in the issuing token if deemed necessary op = operations.Asset_issue( **{ "fee": {"amount": 0, "asset_id": "1.3.0"}, "issuer": to_account["id"], "asset_to_issue": {"amount": int(amount_obj), "asset_id": amount_obj.asset["id"]}, "memo": encrypted_memo, "issue_to_account": to_account["id"], "extensions": [], "prefix": self.bitshares.prefix, } ) log.debug('doing token issuance - address[%s], amount[%s %s], memo[%s]', address, str_amount, self.symbol, memo) # broadcast the transaction self.bitshares.finalizeOp(op, to_account, "active") result = self.bitshares.broadcast() except KeyNotFound as e: raise exceptions.IssuerKeyError(str(e)) except exceptions.AuthorityMissing as e: raise exceptions.IssuerKeyError(str(e)) return { 'txid': None, # transaction ID is not readily available from the Bitshares API 'coin': self.orig_symbol, 'amount': self.get_decimal_from_amount(amount_obj), 'fee': Decimal(0), # fee is in BTS, not the issuing token 'from': address, 'send_type': 'issue' }
from bitshares.blockchain import Blockchain from bitshares.account import Account from bitshares.asset import Asset from bitshares.memo import Memo import btsDiceGameTransactions nodeForConnections = 'wss://api.bitsharesdex.com' blockchain = Blockchain(node=nodeForConnections, mode='head') btsDGT = btsDiceGameTransactions memo = Memo() memo.blockchain.wallet.unlock('superSecretPassword') for op in blockchain.stream(['transfer']): payee = Account(op['to']).name if payee == 'bts-dice-game': payor = Account(op['from']).name decryptedMemo = int(memo.decrypt(op['memo'])) amount = op['amount']['amount'] / 100000 btsDGT.play_game(payor, amount, decryptedMemo)
def cast_money(s, _): if s is None: return None return Decimal(s[1:].replace( ",", "")) # hive off the dollar sign and filter out commas money_type = psycopg2.extensions.new_type((790, ), "MONEY", cast_money) config = ConfigParser() config.read( ['/etc/gateway.conf', os.path.expanduser('~/.config/gateway.conf')]) bitshares = BitShares() bitshares.wallet.unlock(config['gateway']['passphrase']) memoObj = Memo() memoObj.unlock_wallet(config['gateway']['passphrase']) acct = Account(config['gateway']['account']) conn = psycopg2.connect(host=config['db'].get('host', ''), database=config['db']['name'], user=config['db']["user"], cursor_factory=psycopg2.extras.NamedTupleCursor) psycopg2.extensions.register_type(money_type, conn) InputTx = collections.namedtuple("InputTx", "bts_account amount date comment fiat_txid") registry = {}
owner_key = "5JrC9FxgxtJ8fi8UjPgL57KH27ToVngEZ7Aka6uSSNBFb2XTVgB" memo_key = "5KUVfh5zagFRheVT8G4PQXjknw25nuEXizsh3k3JhY3J5cEkq1H" active_key = "5JyorRk13HM1WDJ4VvPE7WimPa4KB21qhLQMTcuZkNxBdafdQnV" bitshares = BitShares(node=["wss://openledger.hk/ws", "wss://us.nodes.bitshares.ws", "wss://bitshares.openledger.info/ws"]) try: bitshares.wallet.create(pass_phrase) bitshares.wallet.addPrivateKey(owner_key) bitshares.wallet.addPrivateKey(active_key) bitshares.wallet.addPrivateKey(memo_key) except: bitshares.wallet.unlock(pass_phrase) acc = bitshares.wallet.getAccounts()[0]['account'] m = Memo(blockchain=bitshares) m.blockchain.wallet.unlock(pass_phrase) def verify_transaction(acc, m, to_send_text, to_send_amount, payment_id, loop_time): starting_time = time.time() while True: started_time = time.time() - starting_time if started_time > loop_time: break ad_object = advertisement.objects.get(id=payment_id) for transaction in acc.history(): currInfo = transaction['op'][1]
def build_transaction(incidentId, fromAddress, fromMemoWif, toAddress, asset_id, amount, includeFee, bitshares_instance=None): """ Builds a transaction (without signature) :param guid incidentId: Lykke unique operation ID :param str fromAddress: Source address :param str toAddress: Destination address :param str assetId: Asset ID to transfer :param str amount: Amount to transfer. Integer as string, aligned to the asset accuracy. Actual value can be calculated as x = amount / (10 ^ asset.Accuracy) :param bool includeFee: Flag, which indicates, that the fee should be included in the specified amount """ def obtain_raw_tx(): # if old_operation is None: _memo = memo.encrypt(memo_plain) _expiration = Config.get("bitshares", "transaction_expiration_in_sec", 60 * 60 * 24) # 24 hours # else: # memo_encrypted = memo.encrypt(memo_plain) op = operations.Transfer(**{ "fee": { "amount": 0, "asset_id": "1.3.0" }, # will be replaced "from": from_account["id"], "to": to_account["id"], "amount": amount.json(), "memo": _memo, "prefix": bitshares_instance.prefix }) tx = TransactionBuilder( bitshares_instance=bitshares_instance ) tx.appendOps(op) tx.set_expiration(_expiration) # Build the transaction, obtain fee to be paid tx.constructTx() return tx.json() operation_formatter.validate_incident_id(incidentId) if not is_valid_address(fromAddress): raise AccountDoesNotExistsException() if not is_valid_address(toAddress): raise AccountDoesNotExistsException() # # check if this was already built # old_operation = None # try: # old_operation = _get_os().get_operation(incidentId) # except OperationNotFoundException: # pass # Decode addresses from_address = split_unique_address(fromAddress) to_address = split_unique_address(toAddress) # obtain chain accounts from addresses from_account = Account( from_address["account_id"], bitshares_instance=bitshares_instance) to_account = Account( to_address["account_id"], bitshares_instance=bitshares_instance) memo_plain = create_memo(from_address, to_address, incidentId) try: # Construct amount amount = Amount( { "amount": amount, "asset_id": asset_id }, bitshares_instance=bitshares_instance ) except AssetDoesNotExistsException: raise AssetNotFoundException() # encrypt memo # TODO this is a hack. python-bitshares issue is opened, once resolve, fix if not fromMemoWif: if from_address["account_id"] == Config.get("bitshares", "exchange_account_id"): fromMemoWif = Config.get("bitshares", "exchange_account_memo_key") if fromMemoWif: bitshares_instance.wallet.setKeys(fromMemoWif) # memo key of the account must be known! if not from_account["options"]["memo_key"] in Wallet.keys: raise MemoMatchingFailedException() memo = Memo( from_account=from_account, to_account=to_account, bitshares_instance=bitshares_instance ) try: tx = obtain_raw_tx() except MissingKeyError: raise MemoMatchingFailedException() fee = Amount(tx["operations"][0][1]["fee"], bitshares_instance=bitshares_instance) # virtual internal transfers always do full amount if includeFee and from_account != to_account: # Reduce fee from amount to transfer amount -= fee tx = obtain_raw_tx() # Add additional/optional information # - add incident_id as fallback for internal database # - add decoded memo to avoid double decoding tx.update({ "incident_id": incidentId, "decoded_memo": memo_plain, }) if bitshares_instance.prefix != "BTS": tx["prefix"] = bitshares_instance.prefix return {"transactionContext": json.dumps(tx)}