# Set up the memo & send the tx

Now that we have our encrypted message, we can send it through the XRPL network.\
\
We'll create a transaction with a minimal amount (1 drop) and include our encrypted message in the transaction's memo field.\
The memo field is perfect for this as it can store arbitrary data, making it an ideal place for our encrypted message.\
\
Once the transaction is validated, our secret message will be securely stored on the blockchain - visible to everyone but readable only by the intended recipient who holds the matching private key.

```typescript
import tweetnacl from 'tweetnacl';
import { Buffer } from "buffer";
import { Client, Wallet, deriveAddress, Payment } from "xrpl";
import {
  edwardsToMontgomeryPub,
  edwardsToMontgomeryPriv,
} from "@noble/curves/ed25519";

const { box, randomBytes } = tweetnacl;

/**
 * Encrypts a message using X25519 (Montgomery curve) for Diffie-Hellman key exchange
 *
 * @param message - Plain text message to encrypt
 * @param recipientPublicKey - Recipient's Ed25519 public key (hex encoded)
 * @param senderSecretKey - Sender's Ed25519 private key (hex encoded)
 * @returns JSON string containing base64 encoded encrypted message and nonce
 *
 * Steps:
 * 1. Convert hex keys to byte arrays
 * 2. Generate random nonce for uniqueness
 * 3. Convert message to bytes
 * 4. Convert Ed25519 keys to X25519 (Montgomery) format for encryption
 * 5. Encrypt using NaCl box with converted keys
 * 6. Return encrypted message and nonce as base64 JSON
 */
export function encryptMessage(
  message: string,
  recipientPublicKey: string,
  senderSecretKey: string,
): string {
  const pubKeyBytes = Buffer.from(recipientPublicKey.slice(2), "hex");
  const secretKeyBytes = Buffer.from(senderSecretKey.slice(2), "hex");

  const nonce = randomBytes(box.nonceLength);
  const messageUint8 = Buffer.from(message);

  const pubKeyCurve = edwardsToMontgomeryPub(pubKeyBytes);
  const privKeyCurve = edwardsToMontgomeryPriv(secretKeyBytes);

  const encryptedMessage = box(messageUint8, nonce, pubKeyCurve, privKeyCurve);

  return JSON.stringify({
    encrypted: Buffer.from(encryptedMessage).toString("base64"),
    nonce: Buffer.from(nonce).toString("base64"),
  });
}

/**
 * Sends an XRPL transaction containing an encrypted message in its memo field
 *
 * @param cypherMessage - The encrypted message to send
 * @param myWallet - Sender's XRPL wallet for signing the transaction
 * @param receiverPubKey - Recipient's public key to derive their XRPL address
 * @returns Transaction result or undefined if error occurs
 *
 * Flow:
 * 1. Connect to XRPL testnet
 * 2. Create Payment transaction:
 *    - Minimal amount (1 drop)
 *    - Include encrypted message in memo field
 *    - Derive recipient's address from their public key
 * 3. Prepare, sign and submit transaction
 * 4. Wait for validation and return result
 * 5. Always disconnect client when done
 *
 * Note: MemoType is hex encoded "http://example.com/memo/generic"
 */

async function sendTX(
  cypherMessage: string,
  myWallet: Wallet,
  recipientPublicKey: string,
) {
  const client = new Client("wss://clio.altnet.rippletest.net:51233/");
  try {
    await client.connect();
    const receiverAddress = deriveAddress(recipientPublicKey);

    const tx: Payment = {
      TransactionType: "Payment",
      Account: myWallet.classicAddress,
      Destination: receiverAddress,
      Amount: "10000000",
      Memos: [
        {
          Memo: {
            MemoData: Buffer.from(cypherMessage).toString("hex"),
          },
        },
      ],
    };

    const prepared = await client.autofill(tx);
    const signed = myWallet.sign(prepared);
    const result = await client.submitAndWait(signed.tx_blob);

    return result;
  } catch (error) {
    console.log(error);
  } finally {
    await client.disconnect();
  }
}

async function main(): Promise<void> {
  const recipientPublicKey = "Recipient public key goes here";
  const myWallet = Wallet.fromSeed("Your seed goes here");

  const cypherMessage = encryptMessage(
    "Hello World",
    recipientPublicKey,
    myWallet.privateKey,
  );

  console.log("==============CYPHERED MESSAGE==============");
  console.log(cypherMessage);

  const tx = await sendTX(cypherMessage, myWallet, recipientPublicKey);

  console.log("==============TRANSACTION==============");
  console.log(tx);

  console.log("all done");
}

main();

```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.xrpl-commons.org/cyphered-chat-on-xrpl/set-up-the-memo-and-send-the-tx.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
