def check_contract(prev_tx, prev_vout, contract_hash, asset): a = wally.hex_from_bytes(wally.hex_to_bytes(prev_tx)[::-1])+wally.hex_from_bytes(struct.pack('<L', int(prev_vout))) a = wally.hex_from_bytes(wally.sha256d(wally.hex_to_bytes(a))) b = a + contract_hash merkle = wally.hex_from_bytes(wally.sha256_midstate(wally.hex_to_bytes(b))) c = merkle + '0000000000000000000000000000000000000000000000000000000000000000' asset_id = wally.hex_from_bytes(wally.sha256_midstate(wally.hex_to_bytes(c))[::-1]) return(asset_id == asset)
def __init__(self, pubkeys, testnet): self.redeem_script = get_redeem_script(pubkeys) self.redeem_script_hex = wally.hex_from_bytes(self.redeem_script) script_hash = wally.hash160(self.get_witness_script()) script_hash_hex = wally.hex_from_bytes(script_hash) self.scriptPubKey = get_scriptpubkey_hex(script_hash_hex) ver = b'\xc4' if testnet else b'\x05' self.address = wally.base58check_from_bytes(ver + script_hash)
def __init__(self, pubkeys, network): self.redeem_script = get_redeem_script(pubkeys) self.redeem_script_hex = wally.hex_from_bytes(self.redeem_script) script_hash = wally.hash160(self.get_witness_script()) script_hash_hex = wally.hex_from_bytes(script_hash) self.scriptPubKey = get_scriptpubkey_hex(script_hash_hex) ver = {'testnet': b'\xc4', 'mainnet': b'\x05'}[network] self.address = wally.base58check_from_bytes(ver + script_hash)
def gait_paths_from_seed(seed): """Get the paths for deriving the GreenAddress xpubs from a hex seed, rather than mnemonic This is an alternative derivation path used with hardware wallets where the mnemonic may not be available. It is based on a hardened public key derived from the backed up hw wallet seed. Returns two possible paths corresponding to two different client implementations. """ assert len(seed) == wally.BIP39_SEED_LEN_512 # Passing version=BIP32_VER_MAIN_PRIVATE here although it may be either MAIN or TEST # This version indicator only matters if you serialize the key version = wally.BIP32_VER_MAIN_PRIVATE root_key = wally.bip32_key_from_seed(seed, version, wally.BIP32_FLAG_SKIP_HASH) # path = m/18241' # 18241 = 0x4741 = 'GA' flags = wally.BIP32_FLAG_KEY_PUBLIC | wally.BIP32_FLAG_SKIP_HASH path = [gaconstants.HARDENED | 18241] derived_public_key = wally.bip32_key_from_parent_path(root_key, path, flags) chain_code = wally.bip32_key_get_chain_code(derived_public_key) pub_key = wally.bip32_key_get_pub_key(derived_public_key) # For historic reasons some old clients use a hexlified input path here - generate both path_input = chain_code + pub_key path_input_hex = bytearray(wally.hex_from_bytes(chain_code + pub_key), 'ascii') return [get_gait_path(path_input) for path_input in [path_input, path_input_hex]]
def _sign_tx(self, details, wally_tx): txdetails = details['transaction'] utxos = txdetails['used_utxos'] or txdetails['old_used_utxos'] signatures = [] for index, utxo in enumerate(utxos): is_segwit = utxo['script_type'] in [14, 15, 159, 162] # FIXME!! if not is_segwit: # FIXME raise NotImplementedError("Non-segwit input") txhash = self._get_sighash(wally_tx, index, utxo) path = utxo['user_path'] privkey = self.get_privkey(path) signature = wally.ec_sig_from_bytes( privkey, txhash, wally.EC_FLAG_ECDSA | wally.EC_FLAG_GRIND_R) signature = wally.ec_sig_to_der(signature) signature.append(wally.WALLY_SIGHASH_ALL) signatures.append(wally.hex_from_bytes(signature)) logging.debug('Signature (der) input %s path %s: %s', index, path, signature) return {'signatures': signatures}
def sign_tx(self, details): txdetails = details['transaction'] utxos = txdetails['used_utxos'] or txdetails['old_used_utxos'] signatures = [] for index, utxo in enumerate(utxos): wally_tx = wally.tx_from_hex(txdetails['transaction'], wally.WALLY_TX_FLAG_USE_WITNESS) is_segwit = utxo['script_type'] in [14, 15, 159, 162] # FIXME!! if not is_segwit: # FIXME raise NotImplementedError("Non-segwit input") flags = wally.WALLY_TX_FLAG_USE_WITNESS if is_segwit else 0 prevout_script = wally.hex_to_bytes(utxo['prevout_script']) txhash = wally.tx_get_btc_signature_hash(wally_tx, index, prevout_script, utxo['satoshi'], wally.WALLY_SIGHASH_ALL, flags) path = utxo['user_path'] privkey = self.get_privkey(path) signature = wally.ec_sig_from_bytes( privkey, txhash, wally.EC_FLAG_ECDSA | wally.EC_FLAG_GRIND_R) signature = wally.ec_sig_to_der(signature) signature.append(wally.WALLY_SIGHASH_ALL) signatures.append(wally.hex_from_bytes(signature)) logging.debug('Signature (der) input %s path %s: %s', index, path, signature) return json.dumps({'signatures': signatures})
def resolve(self, details): """Resolve a requested action using the device""" logging.debug("%s resolving %s", self.name, details) details = details['required_data'] if details['action'] == 'get_xpubs': xpubs = [] paths = details['paths'] logging.debug('get_xpubs paths = %s', paths) for path in paths: xpub = self.get_xpub(path) logging.debug('xpub for path %s: %s', path, xpub) xpubs.append(xpub) response = json.dumps({'xpubs': xpubs}) logging.debug('resolving: %s', response) return response if details['action'] == 'sign_message': logging.debug('sign message path = %s', details['path']) message = details['message'] logging.debug('signing message "%s"', message) signature = self.sign_message(details['path'], message) signature_hex = wally.hex_from_bytes(signature) result = json.dumps({'signature': signature_hex}) logging.debug('resolving %s', result) return result if details['action'] == 'sign_tx': return self.sign_tx(details) raise NotImplementedError("action = \"{}\"".format(details['action']))
def resolve(self, details): """Resolve a requested action using the device""" logging.debug("%s resolving %s", self.name, details) details = details['required_data'] if details['action'] == 'get_xpubs': xpubs = [] paths = details['paths'] logging.debug('get_xpubs paths = %s', paths) for path in paths: xpub = self.get_xpub(path) logging.debug('xpub for path %s: %s', path, xpub) xpubs.append(xpub) response = json.dumps({'xpubs': xpubs}) logging.debug('resolving: %s', response) return response if details['action'] == 'sign_message': logging.debug('sign message path = %s', details['path']) message = details['message'] logging.debug('signing message "%s"', message) signature = self.sign_message(details['path'], message) signature_hex = wally.hex_from_bytes(signature) result = json.dumps({'signature': signature_hex}) logging.debug('resolving %s', result) return result if details['action'] == 'sign_tx': return self.sign_tx(details) if details['action'] == 'get_receive_address': blinding_script_hash = bytes.fromhex( details['address']['blinding_script_hash']) public_blinding_key = self.get_public_blinding_key( blinding_script_hash) return json.dumps({'blinding_key': public_blinding_key.hex()}) retval = {} if details['action'] == 'create_transaction': blinding_keys = {} change_addresses = details['transaction'].get('change_address', {}) for asset, addr in change_addresses.items(): blinding_script_hash = bytes.fromhex( addr['blinding_script_hash']) blinding_keys[asset] = self.get_public_blinding_key( blinding_script_hash).hex() retval['blinding_keys'] = blinding_keys if 'blinded_scripts' in details: nonces = [] for elem in details['blinded_scripts']: pubkey = bytes.fromhex(elem['pubkey']) script = bytes.fromhex(elem['script']) nonces.append(self.get_shared_nonce(pubkey, script).hex()) retval['nonces'] = nonces if not retval: raise NotImplementedError("action = \"{}\"".format( details['action'])) return json.dumps(retval)
def check_tx(issuance_txid, issuance_vin, asset, explorer): if (explorer): resp = requests.get(url=explorerURL+issuance_txid, verify=True) issuance = resp.json() c = issuance['vin'][issuance_vin]['issuance']['asset_entropy'] + '0000000000000000000000000000000000000000000000000000000000000000' asset_id = wally.hex_from_bytes(wally.sha256_midstate(wally.hex_to_bytes(c))[::-1]) else: issuance = host.call('getrawtransaction', issuance_txid, 1) asset_id = issuance['vin'][issuance_vin]['issuance']['asset'] return(asset_id == asset)
def fixup_old_nlocktimes(self): """Fixup data from old format nlocktimes files Older nlocktimes files do not contain explicit prevout_signatures, prevout_scripts or prevout_script_types. Detect this and extract them from the raw transaction to make the txdata look consistent to the rest of the code. Note that segwit is not being handled here because old style nlocktimes predate segwit """ for txdata in self.txdata: if 'prevout_signatures' not in txdata: tx = txutil.from_hex(txdata['tx']) txdata['prevout_script_types'] = [] txdata['prevout_signatures'] = [] txdata['prevout_scripts'] = [] for i in range(wally.tx_get_num_inputs(tx)): inp = wally.tx_get_input_script(tx, i) ga_signature = wally.hex_from_bytes(inp[2:inp[1]+2]) redeem_script = wally.hex_from_bytes(inp[-71:]) txdata['prevout_signatures'].append(ga_signature) txdata['prevout_scripts'].append(redeem_script) txdata['prevout_script_types'].append(gaconstants.P2SH_FORTIFIED_OUT)
def _get_unspent(self, address): imported = self.imported.get(address, None) if imported is None: return None tx, i = imported script = wally.tx_get_output_script(tx, i) return { "txid": txutil.get_txhash_bin(tx), "vout": i, "address": address, "scriptPubKey": wally.hex_from_bytes(script) }
def __init__(self, pointer): logging.debug('Derive keys for subaccount={}, pointer={}'.format( subaccount, pointer)) self.subaccount = subaccount self.pointer = pointer # Derive the GreenAddress public key for this pointer value ga_key = gacommon.derive_hd_key(ga_xpub, [pointer], wally.BIP32_FLAG_KEY_PUBLIC) self.ga_key = wally.bip32_key_get_pub_key(ga_key) logging.debug("ga_key = {}".format( wally.hex_from_bytes(self.ga_key))) # Derive the user private keys for this pointer value flags = wally.BIP32_FLAG_KEY_PRIVATE user_key_paths = [(key, [pointer]) for key in user_keys] private_keys = [ gacommon.derive_hd_key(*path, flags=flags) for path in user_key_paths ] self.private_keys = [ wally.bip32_key_get_priv_key(k) for k in private_keys ] # Derive the user public keys from the private keys user_public_keys = [ wally.ec_public_key_from_private_key(k) for k in self.private_keys ] public_keys = [self.ga_key] + user_public_keys # Script could be segwit or not - generate both segwit and non-segwit addresses self.witnesses = { cls.type_: cls(public_keys, network) for cls in (P2SH, P2WSH) } logging.debug('p2sh address: {}'.format( self.witnesses['p2sh'].address)) logging.debug('p2wsh address: {}'.format( self.witnesses['p2wsh'].address))
def check_website(domain, asset): asserURL = 'https://'+domain+'/.well-known/liquid-asset-proof-'+asset resp = requests.get(url=asserURL, verify=True) if (re.match(r'^.*'+domain+'.*'+asset, resp.text)): return(True) else: return(False) host = RPCHost(liquidURL) resp = requests.get(url=registryURL, verify=True) assets = resp.json() for asset in assets.keys(): contract = json.dumps(assets[asset]['contract'], separators=(',',':'), sort_keys=True) contract_hash = wally.hex_from_bytes(wally.sha256(contract.encode('ascii'))) prev_tx = assets[asset]['issuance_prevout']['txid'] prev_vout = assets[asset]['issuance_prevout']['vout'] issuance_txid = assets[asset]['issuance_txin']['txid'] issuance_vin = assets[asset]['issuance_txin']['vin'] domain = assets[asset]['contract']['entity']['domain'] if(check_contract(prev_tx, prev_vout, contract_hash, asset)): contract = 'valid contract' else: contract = 'invalid contract' if(check_tx(issuance_txid, issuance_vin, asset, False)): tx = 'valid transaction' else: tx = 'invalid transaction'
def get_redeem_script(keys): """Return a 2of3 multisig redeem script as a hex string""" keys = [wally.hex_from_bytes(key) for key in keys] logging.debug("get_redeem_script public keys = {}".format(keys)) return wally.hex_to_bytes("5221{}21{}21{}53ae".format(*keys))
import argparse import json import logging import sys import wallycore as wally b2h = lambda b: wally.hex_from_bytes(b) h2b = lambda h: wally.hex_to_bytes(h) b2h_rev = lambda b: b2h(b[::-1]) h2b_rev = lambda h: h2b(h)[::-1] def err(s): logging.error(s) sys.exit(1) def parse_tx_file(file): with file as f: try: return wally.tx_from_hex( f.read().strip(), wally.WALLY_TX_FLAG_USE_WITNESS | wally.WALLY_TX_FLAG_USE_ELEMENTS) except ValueError: err("Invalid transaction") def parse_uint256_hex(h): try: b = h2b_rev(h)
def issuer(asset_amount, asset_address, token_amount, token_address, issuer_pubkey, name, ticker, precision, domain): data = {} version = 0 # don't change blind = False feerate = 0.00003000 asset_amount = int(asset_amount) / 10**(8 - int(precision)) token_amount = int(token_amount) / 10**(8 - int(precision)) # Create funded base tx base = host.call('createrawtransaction', [], [{'data': '00'}]) funded = host.call('fundrawtransaction', base, {'feeRate': feerate}) # Create the contact and calculate the asset id (Needed for asset registry!) contract = json.dumps( { 'name': name, 'ticker': ticker, 'precision': int(precision), 'entity': { 'domain': domain }, 'issuer_pubkey': issuer_pubkey, 'version': version }, separators=(',', ':'), sort_keys=True) contract_hash = wally.hex_from_bytes(wally.sha256( contract.encode('ascii'))) data['contract'] = contract # Create the rawissuance transaction contract_hash_rev = wally.hex_from_bytes( wally.hex_to_bytes(contract_hash)[::-1]) rawissue = host.call('rawissueasset', funded['hex'], [{ 'asset_amount': asset_amount, 'asset_address': asset_address, 'token_amount': token_amount, 'token_address': token_address, 'blind': blind, 'contract_hash': contract_hash_rev }]) # Blind the transaction blind = host.call('blindrawtransaction', rawissue[0]['hex'], True, [], False) # Sign transaction signed = host.call('signrawtransactionwithwallet', blind) decoded = host.call('decoderawtransaction', signed['hex']) data['asset_id'] = decoded['vin'][0]['issuance']['asset'] # Test transaction test = host.call('testmempoolaccept', [signed['hex']]) if test[0]['allowed'] is True: txid = host.call('sendrawtransaction', signed['hex']) data['txid'] = txid data['registry'] = json.dumps({ 'asset_id': data['asset_id'], 'contract': json.loads(data['contract']) }) return data
def get_pubkey_for_pointer_hex(xpub): """Return hex encoded public key derived from xpub for pointer""" xpub = gacommon.derive_hd_key(xpub, [pointer], wally.BIP32_FLAG_KEY_PUBLIC) return wally.hex_from_bytes(wally.bip32_key_get_pub_key(xpub))
import wallycore as wally h2b = wally.hex_to_bytes b2h = wally.hex_from_bytes h2b_rev = lambda h: wally.hex_to_bytes(h)[::-1] b2h_rev = lambda b: wally.hex_from_bytes(b[::-1])
def get_txhash_hex(tx): return wally.hex_from_bytes(get_txhash_bin(tx)[::-1])
# Create the contact and calculate the asset id (Needed for asset registry!) contract = json.dumps( { 'name': name, 'ticker': ticker, 'precision': precision, 'entity': { 'domain': domain }, 'issuer_pubkey': issuer_pubkey, 'version': version }, separators=(',', ':'), sort_keys=True) contract_hash = wally.hex_from_bytes(wally.sha256(contract.encode('ascii'))) a = wally.hex_from_bytes( wally.hex_to_bytes(prev_tx)[::-1]) + wally.hex_from_bytes( struct.pack('<L', int(prev_vout))) a = wally.hex_from_bytes(wally.sha256d(wally.hex_to_bytes(a))) b = a + contract_hash merkle = wally.hex_from_bytes(wally.sha256_midstate(wally.hex_to_bytes(b))) c = merkle + '0000000000000000000000000000000000000000000000000000000000000000' merkle = wally.hex_from_bytes( wally.sha256_midstate(wally.hex_to_bytes(c))[::-1]) res['asset_id'] = merkle res['contract'] = contract res['contract_hash'] = contract_hash # Create the rawissuance transaction contract_hash_rev = wally.hex_from_bytes(