lightninglabs / lightninglabs/taproot-assets

Improve recovery UX when courier delivery fails after confirmed receive

Open
#2,143 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement ux
Dominant language
Go
Stars
525
Forks
150
Avg merge
2d 15h
Merged PRs (30d)
31

Description

## No obvious recovery path when proof courier delivery fails after confirmed receive

## Background

While testing a local Alice -> Bob Taproot Asset transfer on regtest, the transfer confirmed on-chain, but Bob never received/imported the proof.

The generated Bob address used the default proof courier:

```text
hashmail://mailbox.terminal.lightning.today:443
```

That courier failed, so proof delivery stayed pending. The bigger issue is that I could manually export and verify the correct proof, but I could not find a way to register/import it into Bob's wallet. Bob remained stuck with `has_proof=false` and no asset balance.

## Environment

```json
{
"version": "0.7.99-alpha commit=",
"lnd_version": "0.20.99-beta",
"network": "regtest"
}
```

Both Alice and Bob were local `lnd`/`tapd` regtest nodes.

## Steps to reproduce

1. Start local Alice and Bob regtest nodes.

2. Mint and finalize an asset on Alice.

3. Sync Bob with Alice's issuance universe:

```sh
./bob-tapd.sh universe sync \
--universe_host 127.0.0.1:10029 \
--asset_id "$ASSET_ID" \
--proof_type issuance
```

4. Bob creates a receive address:

```sh
BOB_ADDR=$(./bob-tapd.sh newaddr "$ASSET_ID" 100 | jq -r .encoded)
```

The generated address contains:

```json
{
"proof_courier_addr": "hashmail://mailbox.terminal.lightning.today:443"
}
```

5. Alice sends to Bob:

```sh
./alice-tapd.sh send "$BOB_ADDR"
```

6. Mine confirmations.

## Actual behavior

Alice's transfer confirms, but proof delivery remains pending:

```json
{
"amount": "100",
"output_type": "OUTPUT_TYPE_SIMPLE",
"script_key_is_local": false,
"proof_delivery_status": "PROOF_DELIVERY_STATUS_PENDING",
"proof_courier_addr": "hashmail://mailbox.terminal.lightning.today:443"
}
```

Bob detects the confirmed receive outpoint, but has no proof:

```json
{
"status": "ADDR_EVENT_STATUS_TRANSACTION_CONFIRMED",
"outpoint": "43be5fa32abecbecbf91995515dfcb626d68923b149bb554452e57877c24e7ae:1",
"confirmation_height": 126,
"has_proof": false
}
```

Bob's balance remains empty:

```json
{
"asset_balances": {},
"asset_group_balances": {},
"unconfirmed_transfers": "0"
}
```

## Manual proof verification works, but does not recover the receive

I exported the proof from Alice for Bob's script key:

```sh
BOB_SCRIPT_KEY=$(
./bob-tapd.sh raw addrs receives \
| jq -r '.events[-1].addr.script_key'
)

./alice-tapd.sh raw proofs export \
--asset_id "$ASSET_ID" \
--script_key "$BOB_SCRIPT_KEY" \
--proof_file /tmp/bob-asset-proof.tap
```

Then verified it with Bob:

```sh
./bob-tapd.sh raw proofs verify \
--proof_file /tmp/bob-asset-proof.tap
```

Bob returned:

```json
{
"valid": true
}
```

So the proof itself appears valid and corresponds to Bob's receive output, but verifying it does not register/import the asset into Bob's wallet.

I also could not find an obvious CLI path to manually import/register that valid proof after courier delivery failed.

## Logs

Alice repeatedly fails to deliver through the default hashmail courier:

```text
PROF: Backing off: proof transfer failed
addr=hashmail://mailbox.terminal.lightning.today:443
transfer_type=send
err="failed to initialize mailboxes: failed to init sender stream mailbox:
rpc error: code = Unavailable desc = connection error:
desc = \"transport: authentication handshake failed: credentials: cannot check peer:
missing selected ALPN property...\""
```

Bob logs show the same issue while trying to receive the proof:

```text
GRDN: Unable to receive proof ... unable to receive proof using courier:
rpc error: code = Unavailable desc = connection error:
desc = "transport: authentication handshake failed: credentials: cannot check peer:
missing selected ALPN property..."
```

## Expected behavior

If courier delivery fails after the receiver detects a confirmed address event, there should be a clear recovery path.

For example:

1. `proofs verify` could optionally register/import the proof when it matches a local receive address;
2. there could be a documented CLI command to manually register/import a valid proof;
3. the receiver could retry proof retrieval from a configurable/local courier;
4. or the address creation flow could make it clearer that using the default public courier may leave local regtest receives unrecoverable without additional setup.

## Actual problem

The receiver reaches this state:

```text
ADDR_EVENT_STATUS_TRANSACTION_CONFIRMED
has_proof=false
```

and even though a valid proof can be exported by the sender and verified by the receiver, there is no obvious way to move Bob's wallet into the received state.

## Question

What is the expected recovery path after proof courier delivery fails?

Is there a supported way to manually register/import a valid proof for a local receive address?

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the CLI entry points described in the issue: raw addrs receives, raw proofs export, and raw proofs verify, then trace the proof courier receive and registration flow. Define a supported recovery path for a confirmed address with has_proof=false, and verify it using the regtest reproduction and the exported proof scenario.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
backend, cli
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.