# SendMessage

Sends a single message to a receiver's mailbox. Requires a valid, unused Bitcoin P2TR transaction outpoint as proof of uniqueness, included in a block as proof of work.

Source: [authmailboxrpc/mailbox.proto](https://github.com/lightninglabs/taproot-assets/blob/0bf1b0f1d89f0cf5b7560389a089728ded156952/taprpc/authmailboxrpc/mailbox.proto#L20)

### gRPC 
```text
rpc SendMessage (SendMessageRequest) returns (SendMessageResponse);
```

### REST 
| HTTP Method | Path |
| --- | --- |
| POST | `/v1/taproot-assets/mailbox/send` |

## Code Samples 
- gRPC
- REST

- Javascript
- Python
- grpcurl

```javascript
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('authmailboxrpc/mailbox.proto', loaderOptions);
const authmailboxrpc = grpc.loadPackageDefinition(packageDefinition).authmailboxrpc;
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 authmailboxrpc.Mailbox(GRPC_HOST, creds);
let request = {
  receiver_id: <bytes>,
  encrypted_payload: <bytes>,
  tx_proof: <BitcoinMerkleInclusionProof>,
};
client.sendMessage(request, function(err, response) {
  console.log(response);
});
// Console output:
//  {
//    "message_id": <uint64>,
//  }
```

```python
import codecs, grpc, os
# Generate the following 2 modules by compiling the authmailboxrpc/mailbox.proto with the grpcio-tools.
# See https://github.com/lightningnetwork/lnd/blob/master/docs/grpc/python.md for instructions.
import mailbox_pb2 as authmailboxrpc, mailbox_pb2_grpc as mailboxstub

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 = mailboxstub.MailboxStub(channel)
request = authmailboxrpc.SendMessageRequest(
  receiver_id=<bytes>,
  encrypted_payload=<bytes>,
  tx_proof=<BitcoinMerkleInclusionProof>,
)
response = stub.SendMessage(request)
print(response)
# {
#    "message_id": <uint64>,
# }
```

```bash
# 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 authmailboxrpc/mailbox.proto \
    -cacert $TLS_PATH \
    -H "macaroon: $(xxd -ps -u -c 1000 $MACAROON_PATH)" \
    -d '{ "receiver_id": BASE64_ENCODED_VALUE, "encrypted_payload": BASE64_ENCODED_VALUE, "tx_proof": <BitcoinMerkleInclusionProof> }' \
    $GRPC_HOST \
    authmailboxrpc.Mailbox/SendMessage
```

- Javascript
- Python
- curl

```javascript
const fs = require('fs');
const request = require('request');

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

let requestBody = {
  receiver_id: <string>, // <bytes> (base64 encoded)
  encrypted_payload: <string>, // <bytes> (base64 encoded)
  tx_proof: <object>, // <BitcoinMerkleInclusionProof>
};
let options = {
  url: `https://${REST_HOST}/v1/taproot-assets/mailbox/send`,
  // 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:
//  {
//    "message_id": <string>, // <uint64>
//  }
```

```python
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/mailbox/send'
macaroon = codecs.encode(open(MACAROON_PATH, 'rb').read(), 'hex')
headers = {'Grpc-Metadata-macaroon': macaroon}
data = {
  'receiver_id': base64.b64encode(<bytes>),
  'encrypted_payload': base64.b64encode(<bytes>),
  'tx_proof': <BitcoinMerkleInclusionProof>,
}
r = requests.post(url, headers=headers, data=json.dumps(data), verify=TLS_PATH)
print(r.json())
# {
#    "message_id": <uint64>,
# }
```

```bash
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 '{ "receiver_id": BASE64_ENCODED_VALUE, "encrypted_payload": BASE64_ENCODED_VALUE, "tx_proof": <BitcoinMerkleInclusionProof> }' \
    https://$REST_HOST/v1/taproot-assets/mailbox/send
```

## Messages 
### authmailboxrpc.SendMessageRequest 
Source: [authmailboxrpc/mailbox.proto](https://github.com/lightninglabs/taproot-assets/blob/0bf1b0f1d89f0cf5b7560389a089728ded156952/taprpc/authmailboxrpc/mailbox.proto#L126)

| Field | gRPC Type | REST Type | REST Placement |
| --- | --- | --- | --- |
| `receiver_id`<br>The public key identifier of the intended receiver (ReceiverID), encoded as the raw bytes of the compressed public key. | `bytes` | `string` | `body` |
| `encrypted_payload`<br>The ECIES encrypted message payload. | `bytes` | `string` | `body` |
| `tx_proof`<br>The Bitcoin Merkle Inclusion Proof used as the sender's authentication. The server MUST perform full validation of this proof: 1. Verify claimed_outpoint.txid_hex matches hash(raw_tx_data). 2. Verify claimed_outpoint.index is valid for the transaction. 3. Verify merkle_proof connects the transaction hash to the raw_block_header_data's Merkle root. 4. Verify block_header validity (e.g., PoW, potentially chain context). 5. Ensure the claimed_outpoint has not been used previously (check used_proofs table). | [`BitcoinMerkleInclusionProof`](/content/api-docs/api/taproot-assets/mailbox/send-message/#authmailboxrpcbitcoinmerkleinclusionproof/index.html) | `object` | `body` |

### authmailboxrpc.SendMessageResponse 
Source: [authmailboxrpc/mailbox.proto](https://github.com/lightninglabs/taproot-assets/blob/0bf1b0f1d89f0cf5b7560389a089728ded156952/taprpc/authmailboxrpc/mailbox.proto#L153)

| Field | gRPC Type | REST Type |
| --- | --- | --- |
| `message_id`<br>The unique ID assigned to the stored message by the server. | `uint64` | `string` |

## Nested Messages 
### authmailboxrpc.BitcoinMerkleInclusionProof 
| Field | gRPC Type | REST Type |
| --- | --- | --- |
| `raw_tx_data`<br>The raw Bitcoin transaction bytes, in standard Bitcoin serialization format, containing the outpoint being claimed. The server will hash this to get the TXID. | `bytes` | `string` |
| `raw_block_header_data`<br>The raw block header bytes (typically 80 bytes) of the block in which the transaction was mined. Contains the Merkle root against which the proof is verified. | `bytes` | `string` |
| `block_height`<br>The height at which the block was mined. This is used to determine the block's validity and to ensure the transaction is not too old. | `uint32` | `integer` |
| `merkle_proof`<br>The Merkle path proving the transaction's inclusion in the block header's Merkle root. | [`MerkleProof`](/content/api-docs/api/taproot-assets/mailbox/send-message/#authmailboxrpcmerkleproof/index.html) | `object` |
| `claimed_outpoint`<br>The specific output within the provided transaction being claimed as the proof "token". The output at the given index must be a P2TR output. The server must verify that the txid_hex matches the hash of the provided transaction data, and that this specific outpoint index exists in the transaction. | [`OutPoint`](/content/api-docs/api/taproot-assets/mailbox/send-message/#taprpcoutpoint/index.html) | `object` |
| `internal_key`<br>The Taproot internal key used to construct the P2TR output that is claimed by the outpoint above. Must be provided alongside the Taproot Merkle root to prove knowledge of the output's construction. | `bytes` | `string` |
| `merkle_root`<br>The Taproot Merkle root, if applicable. This, alongside the internal key, is used to prove knowledge of the output's construction. If this is not provided (empty or nil), a BIP-0086 construction is assumed. | `bytes` | `string` |

### authmailboxrpc.MerkleProof 
| Field | gRPC Type | REST Type |
| --- | --- | --- |
| `sibling_hashes`<br>List of sibling hashes in the Merkle path, ordered from the transaction's sibling up towards the root. Each hash is typically 32 bytes. | `bytes[]` | `array` |
| `bits`<br>The bitmask indicating the direction (left/right) of each sibling hash in the Merkle tree. Each bit corresponds to a sibling hash in the sibling_hashes list. 0 indicates left, 1 indicates right. | `bool[]` | `array` |

### taprpc.OutPoint 
| Field | gRPC Type | REST Type |
| --- | --- | --- |
| `txid`<br>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`<br>The index of the output on the transaction. | `uint32` | `integer` |
