> ## Documentation Index
> Fetch the complete documentation index at: https://docs.delora.build/llms.txt
> Use this file to discover all available pages before exploring further.

# End-to-end Transaction Example (Solana)

> How to request a quote from Delora API and execute the returned Solana transaction

## Quickstart: minimal working example

The following example demonstrates a complete transaction flow:

1. **Fetches a quote** from delora API for token swap
2. **Executes the transaction** using `@solana/web3.js`

> ⚠️ **Security Note**: Never hardcode private keys in production code. Use wallet adapters or secure key management solutions.

<CodeGroup>
  ```ts TypeScript theme={null}
  import { Connection, PublicKey, VersionedTransaction } from '@solana/web3.js';

  const API_URL = 'https://api.delora.build/v1';
  const SOLANA_RPC_URL = 'https://solana-rpc.publicnode.com';

  interface SolanaProvider {
    publicKey: PublicKey;
    signTransaction: (transaction: VersionedTransaction) => Promise<VersionedTransaction>;
    connect: () => Promise<{ publicKey: PublicKey }>;
  }

  const getQuote = async (params: {
    originChainId: number;
    destinationChainId: number;
    amount: string;
    originCurrency: string;
    destinationCurrency: string;
    senderAddress: string;
    receiverAddress?: string;
  }) => {
    const query = new URLSearchParams();
    
    for (const [key, value] of Object.entries(params)) {
      if (value !== undefined) {
        query.append(key, String(value));
      }
    }
    
    const url = `${API_URL}/quotes?${query.toString()}`;
    const response = await fetch(url);
    
    if (!response.ok) {
      throw new Error(`Failed to get quote: ${response.status} ${response.statusText}`);
    }
    
    return response.json();
  };

  export const executeSwap = async (provider: SolanaProvider, connection: Connection) => {
    await provider.connect();
    const walletAddress = provider.publicKey.toString();

    const originChainId = 1000000001;
    const destinationChainId = 1000000001;
    const originCurrency: string = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';
    const destinationCurrency = 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB';
    const amount = (100 * 1e6).toString();

    const quote = await getQuote({
      originChainId,
      destinationChainId,
      amount,
      originCurrency,
      destinationCurrency,
      senderAddress: walletAddress,
      receiverAddress: walletAddress,
    });

    if (!quote.calldata?.data) {
      throw new Error('Transaction data is missing in quote response');
    }

    const transactionBuffer = Uint8Array.from(atob(quote.calldata.data), c => c.charCodeAt(0));
    let transaction: VersionedTransaction;
    
    try {
      transaction = VersionedTransaction.deserialize(transactionBuffer);
    } catch (error: any) {
      throw new Error(`Failed to deserialize transaction: ${error.message}`);
    }

    const signedTransaction = await provider.signTransaction(transaction);

    const signature = await connection.sendRawTransaction(signedTransaction.serialize(), {
      skipPreflight: false,
      maxRetries: 3,
    });

    const latestBlockhash = await connection.getLatestBlockhash('confirmed');
    const confirmation = await connection.confirmTransaction({
      signature,
      blockhash: latestBlockhash.blockhash,
      lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
    }, 'confirmed');
    
    if (confirmation.value.err) {
      throw new Error(`Transaction failed: ${JSON.stringify(confirmation.value.err)}`);
    }
    
    return signature;
  };
  ```
</CodeGroup>

## React Integration Example

For React applications, you can integrate the swap function as follows:

<CodeGroup>
  ```tsx TypeScript React theme={null}
  import { Connection } from '@solana/web3.js';
  import { executeSwap } from './example';

  const SwapButton = () => {
    const handleSwap = async () => {
      if (!window.solana) {
        alert('Please install Phantom or another Solana wallet');
        return;
      }
      
      const connection = new Connection('https://solana-rpc.publicnode.com', 'confirmed');
      
      try {
        const signature = await executeSwap(window.solana, connection);
        console.log('Transaction signature:', signature);
      } catch (error) {
        console.error('Swap failed:', error);
      }
    };

    return (
      <button onClick={handleSwap}>
        Execute Swap
      </button>
    );
  };
  ```
</CodeGroup>

## Breaking it down

### 1. Building the quote request

The `getQuote` function constructs a query string from parameters and fetches the quote from the API:

`senderAddress` is required, while `receiverAddress` is optional for same-type routes like this one and defaults to `senderAddress`.

<CodeGroup>
  ```ts TypeScript theme={null}
  const getQuote = async (params: {
    originChainId: number;
    destinationChainId: number;
    amount: string;
    originCurrency: string;
    destinationCurrency: string;
    senderAddress: string;
    receiverAddress?: string;
  }) => {
    const query = new URLSearchParams();
    
    for (const [key, value] of Object.entries(params)) {
      if (value !== undefined) {
        query.append(key, String(value));
      }
    }
    
    const url = `${API_URL}/quotes?${query.toString()}`;
    const response = await fetch(url);
    
    if (!response.ok) {
      throw new Error(`Failed to get quote: ${response.status} ${response.statusText}`);
    }
    
    return response.json();
  };
  ```
</CodeGroup>

**Key parameters:**

* `originChainId` / `destinationChainId`: Chain IDs (`1000000001` for Solana)
* `amount`: Token amount in smallest unit (e.g., `"100000000"` for 100 USDC with 6 decimals)
* `originCurrency` / `destinationCurrency`: SPL token mint addresses (e.g., `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` for USDC)
* `senderAddress`: Required Solana wallet address (base58 encoded)
* `receiverAddress`: Optional for same-type routes; defaults to `senderAddress`. For routes across different chain types, provide it explicitly.

### 2. Wallet provider setup

The function accepts a `SolanaProvider` interface, which can be obtained from various sources:

**Browser extension (Phantom, Solflare, etc.):**

```ts theme={null}
const provider = window.solana; // Phantom or other wallet adapter
await provider.connect();
```

**Wallet adapter (React):**

```ts theme={null}
import { useWallet } from '@solana/wallet-adapter-react';

const { wallet, publicKey, signTransaction } = useWallet();
const provider = {
  publicKey,
  signTransaction,
  connect: async () => ({ publicKey }),
};
```

**Keypair (development only):**

```ts theme={null}
import { Keypair } from '@solana/web3.js';

const keypair = Keypair.fromSecretKey(/* your secret key */);
const provider = {
  publicKey: keypair.publicKey,
  signTransaction: async (tx: VersionedTransaction) => {
    tx.sign([keypair]);
    return tx;
  },
  connect: async () => ({ publicKey: keypair.publicKey }),
};
```

> ⚠️ **Never hardcode private keys or secret keys in production code.**

### 3. Transaction deserialization

The quote response contains a base64-encoded `VersionedTransaction` that needs to be decoded:

<CodeGroup>
  ```ts TypeScript theme={null}
  if (!quote.calldata?.data) {
    throw new Error('Transaction data is missing in quote response');
  }

  const transactionBuffer = Uint8Array.from(atob(quote.calldata.data), c => c.charCodeAt(0));
  let transaction: VersionedTransaction;

  try {
    transaction = VersionedTransaction.deserialize(transactionBuffer);
  } catch (error: any) {
    throw new Error(`Failed to deserialize transaction: ${error.message}`);
  }
  ```
</CodeGroup>

**Notes:**

* Use `Uint8Array.from(atob(...))` instead of `Buffer.from()` for browser compatibility
* The transaction is already prepared with all necessary instructions
* Always wrap deserialization in try-catch for error handling

### 4. Transaction signing and execution

Sign the transaction with the wallet provider and send it to the network:

<CodeGroup>
  ```ts TypeScript theme={null}
  const signedTransaction = await provider.signTransaction(transaction);

  const signature = await connection.sendRawTransaction(signedTransaction.serialize(), {
    skipPreflight: false,
    maxRetries: 3,
  });

  const latestBlockhash = await connection.getLatestBlockhash('confirmed');
  const confirmation = await connection.confirmTransaction({
    signature,
    blockhash: latestBlockhash.blockhash,
    lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
  }, 'confirmed');

  if (confirmation.value.err) {
    throw new Error(`Transaction failed: ${JSON.stringify(confirmation.value.err)}`);
  }

  return signature;
  ```
</CodeGroup>
