VerifyAssetOwnership

VerifyAssetOwnership verifies the asset ownership proof embedded in the given transition proof of an asset and returns true if the proof is valid.

Source: assetwalletrpc/assetwallet.proto

gRPC

rpc VerifyAssetOwnership (VerifyAssetOwnershipRequest) returns (VerifyAssetOwnershipResponse);

REST

HTTP Method Path
POST /v1/taproot-assets/wallet/ownership/verify

Code Samples

  • gRPC

  • REST

  • tapcli

  • Javascript

  • Python

  • grpcurl

const fs = require('fs');
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');

const GRPC_HOST = 'localhost:10029'
const MACAROON_PATH = 'TAPD_DIR/data/regtest/admin.macaroon'
const TLS_PATH = 'TAPD_DIR/tls.cert'

const loaderOptions = {
  keepCase: true,
  longs: String,
  enums: String,
  defaults: true,
  oneofs: true,
};
const packageDefinition = protoLoader.loadSync('assetwalletrpc/assetwallet.proto', loaderOptions);
const assetwalletrpc = grpc.loadPackageDefinition(packageDefinition).assetwalletrpc;
process.env.GRPC_SSL_CIPHER_SUITES = 'HIGH+ECDSA';
const tlsCert = fs.readFileSync(TLS_PATH);
const sslCreds = grpc.credentials.createSsl(tlsCert);
const macaroon = fs.readFileSync(MACAROON_PATH).toString('hex');
const macaroonCreds = grpc.credentials.createFromMetadataGenerator(function(args, callback) {
  let metadata = new grpc.Metadata();
  metadata.add('macaroon', macaroon);
  callback(null, metadata);
});
let creds = grpc.credentials.combineChannelCredentials(sslCreds, macaroonCreds);
let client = new assetwalletrpc.AssetWallet(GRPC_HOST, creds);
let request = {
  proof_with_witness: <bytes>,
  challenge: <bytes>,
};
client.verifyAssetOwnership(request, function(err, response) {
  console.log(response);
});
// Console output:
//  {
//    "valid_proof": <bool>,
//    "outpoint": <OutPoint>,
//    "outpoint_str": <string>,
//    "block_hash": <bytes>,
//    "block_hash_str": <string>,
//    "block_height": <uint32>,
//  }
import codecs, grpc, os
# Generate the following 2 modules by compiling the assetwalletrpc/assetwallet.proto with the grpcio-tools.
# See https://github.com/lightningnetwork/lnd/blob/master/docs/grpc/python.md for instructions.
import assetwallet_pb2 as assetwalletrpc, assetwallet_pb2_grpc as assetwalletstub

GRPC_HOST = 'localhost:10029'
MACAROON_PATH = 'TAPD_DIR/data/regtest/admin.macaroon'
TLS_PATH = 'TAPD_DIR/tls.cert'

# create macaroon credentials
macaroon = codecs.encode(open(MACAROON_PATH, 'rb').read(), 'hex')
def metadata_callback(context, callback):
  callback([('macaroon', macaroon)], None)
auth_creds = grpc.metadata_call_credentials(metadata_callback)
# create SSL credentials
os.environ['GRPC_SSL_CIPHER_SUITES'] = 'HIGH+ECDSA'
cert = open(TLS_PATH, 'rb').read()
ssl_creds = grpc.ssl_channel_credentials(cert)
# combine macaroon and SSL credentials
combined_creds = grpc.composite_channel_credentials(ssl_creds, auth_creds)
# make the request
channel = grpc.secure_channel(GRPC_HOST, combined_creds)
stub = assetwalletstub.AssetWalletStub(channel)
request = assetwalletrpc.VerifyAssetOwnershipRequest(
  proof_with_witness=<bytes>,
  challenge=<bytes>,
)
response = stub.VerifyAssetOwnership(request)
print(response)
# {
#    "valid_proof": <bool>,
#    "outpoint": <OutPoint>,
#    "outpoint_str": <string>,
#    "block_hash": <bytes>,
#    "block_hash_str": <string>,
#    "block_height": <uint32>,
# }
# grpcurl docs: https://github.com/fullstorydev/grpcurl
# Proto source: https://github.com/lightninglabs/taproot-assets
GRPC_HOST=localhost:10029
TAPD_DIR=~/.tapd
TAPD_SOURCE=path/to/taproot-assets
NETWORK=mainnet
MACAROON_PATH="$TAPD_DIR/data/$NETWORK/admin.macaroon"
TLS_PATH="$TAPD_DIR/tls.cert"

grpcurl \
    -import-path $TAPD_SOURCE/taprpc/ \
    -proto assetwalletrpc/assetwallet.proto \
    -cacert $TLS_PATH \
    -H "macaroon: $(xxd -ps -u -c 1000 $MACAROON_PATH)" \
    -d '{ "proof_with_witness": BASE64_ENCODED_VALUE, "challenge": BASE64_ENCODED_VALUE }' \
    $GRPC_HOST \
    assetwalletrpc.AssetWallet/VerifyAssetOwnership
const fs = require('fs');
const request = require('request');

const REST_HOST = 'localhost:8089'
const MACAROON_PATH = 'TAPD_DIR/data/regtest/admin.macaroon'

let requestBody = {
  proof_with_witness: <string>, // <bytes> (base64 encoded)
  challenge: <string>, // <bytes> (base64 encoded)
};
let options = {
  url: `https://${REST_HOST}/v1/taproot-assets/wallet/ownership/verify`,
  // Work-around for self-signed certificates.
  rejectUnauthorized: false,
  json: true,
  headers: {
    'Grpc-Metadata-macaroon': fs.readFileSync(MACAROON_PATH).toString('hex'),
  },
  form: JSON.stringify(requestBody),
}
request.post(options, function(error, response, body) {
  console.log(body);
});
// Console output:
//  {
//    "valid_proof": <boolean>, // <bool>
//    "outpoint": <object>, // <OutPoint>
//    "outpoint_str": <string>, // <string>
//    "block_hash": <string>, // <bytes>
//    "block_hash_str": <string>, // <string>
//    "block_height": <integer>, // <uint32>
//  }
import base64, codecs, json, requests

REST_HOST = 'localhost:8089'
MACAROON_PATH = 'TAPD_DIR/data/regtest/admin.macaroon'
TLS_PATH = 'TAPD_DIR/tls.cert'

url = f'https://{REST_HOST}/v1/taproot-assets/wallet/ownership/verify'
macaroon = codecs.encode(open(MACAROON_PATH, 'rb').read(), 'hex')
headers = {'Grpc-Metadata-macaroon': macaroon}
data = {
  'proof_with_witness': base64.b64encode(<bytes>),
  'challenge': base64.b64encode(<bytes>),
}
r = requests.post(url, headers=headers, data=json.dumps(data), verify=TLS_PATH)
print(r.json())
# {
#    "valid_proof": <bool>,
#    "outpoint": <OutPoint>,
#    "outpoint_str": <string>,
#    "block_hash": <bytes>,
#    "block_hash_str": <string>,
#    "block_height": <uint32>,
# }
REST_HOST=localhost:8089
TAPD_DIR=~/.tapd
NETWORK=mainnet
MACAROON_PATH="$TAPD_DIR/data/$NETWORK/admin.macaroon"
TLS_PATH="$TAPD_DIR/tls.cert"

curl -X POST \
    --cacert $TLS_PATH \
    -H "Grpc-Metadata-macaroon: $(xxd -ps -u -c 1000 $MACAROON_PATH)" \
    -d '{ "proof_with_witness": BASE64_ENCODED_VALUE, "challenge": BASE64_ENCODED_VALUE }' \
    https://$REST_HOST/v1/taproot-assets/wallet/ownership/verify
$ tapcli proofs verifyownership --help

NAME:
   tapcli proofs verifyownership - verify a taproot asset ownership proof

USAGE:
   tapcli proofs verifyownership [command options] [arguments...]

DESCRIPTION:

Verify a taproot asset ownership proof. The proof does not contain the
  full asset provenance, only the last state transition proof. But that
  proof contains a signature to prove the asset can be spent by the
  creator of the proof. This command verifies that signature.

OPTIONS:
   --proof_file value  the path to the ownership proof file on disk; use the dash character (-) to read from stdin instead

Messages

assetwalletrpc.VerifyAssetOwnershipRequest

Source: assetwalletrpc/assetwallet.proto

Field gRPC Type REST Type REST Placement
proof_with_witness
The full ownership proof that was generated, including the witness data that contains the proving signature.
bytes string body
challenge
An optional 32-byte challenge that may be used to check the ownership proof against. This challenge must match the one that the prover used on the ProveAssetOwnership RPC.
bytes string body

assetwalletrpc.VerifyAssetOwnershipResponse

Source: assetwalletrpc/assetwallet.proto

Field gRPC Type REST Type
valid_proof
Whether the ownership proof is valid or not.
bool boolean
outpoint
The outpoint the proof commits to.
OutPoint object
outpoint_str
The outpoint in the human-readable form "hash:index".
string string
block_hash
The block hash the output is part of.
bytes string
block_hash_str
The block hash as hexadecimal string of the byte-reversed hash.
string string
block_height
The block height of the block the output is part of.
uint32 integer

Nested Messages

taprpc.OutPoint

Field gRPC Type REST Type
txid
Raw bytes representing the transaction id. Must be in internal byte order (little-endian), i.e. reversed compared to the human-readable (RPC/block explorer) hex encoding.
bytes string
output_index
The index of the output on the transaction.
uint32 integer