示例#1
0
    def _get_blinding_factors(self, txdetails, wally_tx):
        utxos = txdetails['used_utxos'] or txdetails['old_used_utxos']

        for i, o in enumerate(txdetails['transaction_outputs']):
            o['wally_index'] = i

        blinded_outputs = [
            o for o in txdetails['transaction_outputs'] if not o['is_fee']
        ]
        for output in blinded_outputs:
            # TODO: the derivation dance
            # the following values are in display order, reverse them when converting to bytes
            output['assetblinder'] = os.urandom(32).hex()
            output['amountblinder'] = os.urandom(32).hex()

        endpoints = utxos + blinded_outputs
        values = [endpoint['satoshi'] for endpoint in endpoints]
        abfs = b''.join(
            bytes.fromhex(endpoint['assetblinder'])[::-1]
            for endpoint in endpoints)
        vbfs = b''.join(
            bytes.fromhex(endpoint['amountblinder'])[::-1]
            for endpoint in endpoints[:-1])
        final_vbf = wally.asset_final_vbf(values, len(utxos), abfs, vbfs)
        blinded_outputs[-1]['amountblinder'] = final_vbf[::-1].hex()

        for o in blinded_outputs:
            asset_commitment = wally.asset_generator_from_bytes(
                bytes.fromhex(o['asset_id'])[::-1],
                bytes.fromhex(o['assetblinder'])[::-1])
            value_commitment = wally.asset_value_commitment(
                o['satoshi'],
                bytes.fromhex(o['amountblinder'])[::-1], asset_commitment)

            o['asset_commitment'] = asset_commitment.hex()
            o['value_commitment'] = value_commitment.hex()

            # Write the commitments into the wally tx for signing
            wally.tx_set_output_asset(wally_tx, o['wally_index'],
                                      asset_commitment)
            wally.tx_set_output_value(wally_tx, o['wally_index'],
                                      value_commitment)

        retval = {}
        for key in [
                'assetblinders', 'amountblinders', 'asset_commitments',
                'value_commitments'
        ]:
            # gdk expects to get an empty entry for the fee output too, hence this is over the
            # transaction outputs, not just the blinded outputs (fee will just have empty
            # strings)
            retval[key] = [
                o.get(key[:-1], '') for o in txdetails['transaction_outputs']
            ]
        return retval
示例#2
0
def main():
    parser = argparse.ArgumentParser()

    parser.add_argument(
        "-n",
        "--node-url",
        help="Elements node URL, eg http://USERNAME:PASSWORD@HOST:PORT/",
        required=True)
    parser.add_argument("-u", "--utxo", help="txid:vout", required=True)
    parser.add_argument("-a",
                        "--asset",
                        help="asset to receive",
                        required=True)
    parser.add_argument("-r",
                        "--rate",
                        type=float,
                        help="price_asset_send/price_asset_receive",
                        required=True)

    args = parser.parse_args()

    txid, vout = args.utxo.split(":")
    vout = int(vout)
    asset_receive, rate = args.asset, args.rate

    connection = RPCHost(args.node_url)

    unspents = connection.call("listunspent")
    utxo = [u for u in unspents if u["txid"] == txid and u["vout"] == vout][0]

    amount_receive = round(rate * utxo["amount"], 8)
    address = connection.call("getnewaddress")

    tx = connection.call("createrawtransaction", [{
        "txid": txid,
        "vout": vout,
        "sequence": 0xffffffff
    }], {address: amount_receive}, 0, False, {address: asset_receive})

    asset_blinder_bytes = os.urandom(32)
    amount_blinder_bytes = os.urandom(32)
    asset_commitment = wally.asset_generator_from_bytes(
        h2b_rev(asset_receive), asset_blinder_bytes)
    amount_commitment = wally.asset_value_commitment(btc2sat(amount_receive),
                                                     amount_blinder_bytes,
                                                     asset_commitment)

    tx_ = wally.tx_from_hex(
        tx, wally.WALLY_TX_FLAG_USE_WITNESS | wally.WALLY_TX_FLAG_USE_ELEMENTS)
    wally.tx_set_output_asset(tx_, 0, asset_commitment)
    wally.tx_set_output_value(tx_, 0, amount_commitment)
    tx = wally.tx_to_hex(
        tx_,
        wally.WALLY_TX_FLAG_USE_WITNESS | wally.WALLY_TX_FLAG_USE_ELEMENTS)

    ret = connection.call("signrawtransactionwithwallet", tx, None,
                          "SINGLE|ANYONECANPAY")

    assert ret["complete"]
    print(
        json.dumps(
            {
                "tx":
                ret["hex"],
                "inputs": [{
                    "asset": utxo["asset"],
                    "amount": btc2sat(utxo["amount"]),
                    "asset_blinder": utxo["assetblinder"],
                    "amount_blinder": utxo["amountblinder"],
                }],
                "outputs": [{
                    "asset": asset_receive,
                    "amount": btc2sat(amount_receive),
                    "asset_blinder": b2h_rev(asset_blinder_bytes),
                    "amount_blinder": b2h_rev(amount_blinder_bytes),
                }],
            },
            separators=(',', ':')))