> For the complete documentation index, see [llms.txt](https://brick-protocol.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://brick-protocol.gitbook.io/docs/fundamentals/typescript-sdk/transaction-construction.md).

# Transaction construction

Most of accounts used by the program are PDAs. The SDK automatically derives these accounts from the provided arguments, reducing the account management.&#x20;

Presently, my setup involves a server responsible for delivering serialized transactions to the client or application. When the client sends specific parameters through a request, the server responds by providing a pre-built and serialized transaction using the SDK. [Check code](https://github.com/ricardocr987/brick/tree/master/transaction-builder).

#### Create a product:

```typescript
app.get('/initProductTree', async (req: Request, res: Response) => {
    try {
        if (!rpc) res.status(500).send({error: 'Error: Server rpc not configured'});
        const connection = new Connection(rpc);
        const { signer, marketplace, paymentMint, params } = req.query;
        if (!signer || !marketplace || !paymentMint) {
            res.status(500).send({error: 'Error: Missing account'});
        }
        const accounts = {
            signer: new PublicKey(signer),
            marketplace: new PublicKey(marketplace),
            paymentMint: new PublicKey(paymentMint)
        };
        const normalizedParams = {
            id: String(params.id),
            productPrice: Number(params.productPrice),
            feeBasisPoints: Number(params.feeBasisPoints),
            height: Number(params.height),
            buffer: Number(params.buffer),
            canopy: Number(params.canopy),
            name: String(params.name), 
            metadataUrl: String(params.metadataUrl),
        };
        const transaction = await createInitProductTreeTransaction(
            connection, 
            accounts,
            normalizedParams
        );

        res.status(200).send({ 
            transaction: Buffer.from(transaction.serialize()).toString('base64') 
        });
    } catch (error) {
        console.log(error)
        res.status(500).send({ error: error.message });
    }
});
```

#### Registering a purchase:

```typescript
app.get('/registerBuy', async (req: Request, res: Response) => {
    try {
        if (!rpc) throw new Error('Error: Server rpc not configured');
        const connection = new Connection(rpc);

        const { signer, marketplace, productId, paymentMint, seller, marketplaceAuth, params } = req.query;
        if (!signer || !marketplace || !paymentMint || !productId || !seller || !marketplaceAuth || !params) {
          throw new Error('Error: Missing required information');
        }        
        if (!messagesKey) throw new Error('Error: MessagesKey not configured');
        const messagesSigner = ImportAccountFromPrivateKey(Uint8Array.from(JSON.parse(messagesKey)));

        if (!indexerApi) throw new Error('Error: Indexer server not configured');

        const [firstId, secondId] = getSplitId(productId);
        const marketKey = new PublicKey(marketplace);
        const [product] = PublicKey.findProgramAddressSync(
            [
              Buffer.from("product", "utf-8"), 
              firstId, 
              secondId,
              marketKey.toBuffer()
            ],
            BRICK_PROGRAM_ID_PK
        );
        const productResponse = await queryAccounts(indexerApi, { accounts: [product.toString()] });
        const productInfo = productResponse[0].data as Product;
        const itemHash = await generateAlephMessage({ 
            product: product.toString(), 
            seller, signer, 
            units: Number(params.amount), 
            paymentMint, 
            totalAmount: Number(productInfo.sellerConfig.productPrice) * params.amount 
        }, messagesSigner);
        const accounts = {
            signer: new PublicKey(signer),
            marketplace: new PublicKey(marketplace),
            product: new PublicKey(product),
            paymentMint: new PublicKey(paymentMint),
            seller: new PublicKey(seller),
            marketplaceAuth: new PublicKey(marketplaceAuth),
            merkleTree: new PublicKey(productInfo.merkleTree),
        };
        const parsedParams = {
            rewardsActive: params.rewardsActive === 'true' ? true : false,
            amount: Number(params.amount),
            name: params.name,
            uri: `https://api1.aleph.im/api/v0/messages.json?hashes=${itemHash}`,
        };
        const transaction = await createRegisterBuyCnftTransaction(connection, accounts, parsedParams);     

        res.status(200).send({ transaction: Buffer.from(transaction.serialize()).toString('base64') });
    } catch (error) {
        res.status(500).send({ error: error.message });
    }
});

function getSplitId(str: string): [Buffer, Buffer]{
    const bytes = new TextEncoder().encode(str);
  
    const data = new Uint8Array(64);
    data.fill(32);
    data.set(bytes);
  
    const firstId = Buffer.from(data.slice(0, 32));
    const secondId = Buffer.from(data.slice(32));
  
    return [firstId, secondId];
}
```

#### Create a marketplace:

I am using a [solana playground repo](https://github.com/ricardocr987/solana-playground) with more scripts calling more Brick program instructions.

With the following script you can create a marketplace:

<pre class="language-typescript"><code class="lang-typescript"><strong>import { PaymentFeePayer } from "./utils/solita/brick/index.js";
</strong>import { Connection, Keypair } from "@solana/web3.js";
import { FNET_MINT } from "./constants.js";
import dotenv from 'dotenv';
import { createInitMarketplaceTransaction } from "brick-protocol";
dotenv.config();

async function initMarketplace() {
    const rpc = process.env.rpc || '';
    if (rpc === '') throw new Error("RPC not found in environment variables.");

    const secret = JSON.parse(process.env.secret || '');
    if (secret === '') throw new Error("Secret not found in environment variables.");

    const secretUint8Array = new Uint8Array(secret);
    const signer = Keypair.fromSecretKey(secretUint8Array);
    const connection: Connection = new Connection(rpc);

    const accounts = {
        signer: signer.publicKey,
        rewardMint: FNET_MINT,
        discountMint: FNET_MINT,
    };
    const args = {
        fee: 100,
        feeReduction: 20,
        sellerReward: 10,
        buyerReward: 10,
        useCnfts: true,
        deliverToken: false,
        transferable: false,
        chainCounter: false,
        permissionless: false,
        rewardsEnabled: false,
        feePayer: PaymentFeePayer.Buyer,
    };

    const transaction = await createInitMarketplaceTransaction(connection, accounts, args);
    transaction.sign([signer]);
    console.log(transaction)
    const txid = await connection.sendTransaction(transaction);
    console.log(`https://explorer.solana.com/tx/${txid}?cluster=mainnet`);
}

initMarketplace();
</code></pre>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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://brick-protocol.gitbook.io/docs/fundamentals/typescript-sdk/transaction-construction.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.
