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

# Destination Payload Execution

> Execute arbitrary contract calls on the destination chain after transfers

Destination payload lets you execute arbitrary contract calls on the destination chain after a crosschain transfer completes. This is useful for flows such as depositing to a vault, repaying a loan, or interacting with a protocol immediately after bridging or swapping.

<Info>
  Destination payload execution is available on Socket Swap V3 through `/v3/swap/quote`.
</Info>

## How it works

When building a Socket request, you can provide calldata that will be executed on the destination chain after assets are delivered. It works for both same-chain swaps and cross-chain swaps.

Provide these parameters in your quote request:

* `destinationPayload`: ABI-encoded calldata for the target contract on the destination chain
* `receiverAddress`: The execution target that will receive the calldata and perform the call
* `destinationGasLimit`: Gas budget on destination to execute the payload

```solidity theme={null}
interface IBungeeExecutor {
    function executeData(
        bytes32 requestHash,
        uint256[] calldata amounts,
        address[] calldata tokens,
        bytes memory callData
    ) external payable;
}
```

## Implementation example

```typescript theme={null}
const SOCKET_API_BASE_URL = "https://dedicated-backend.socket.tech";
const SOCKET_AFFILIATE_ID = "YOUR_AFFILIATE_ID";
const CONTRACT_ADDRESS = "0x1111111111111111111111111111111111111111";

async function getQuoteWithDestinationPayload() {
  const quoteParams = {
    userOps: "tx",
    userAddress: "0xYourUsersAddress",
    originChainId: "8453",  // Base
    destinationChainId: "8453",  // Base
    inputToken: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",  // USDC on Base
    outputToken: "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2", // USDT on Base
    inputAmount: "10000000",  // 10 USDC (6 decimals)
    receiverAddress: CONTRACT_ADDRESS, // contract implementing IBungeeExecutor.executeData
    destinationPayload: "0x1234acbd", // calldata for the receiver contract
    destinationGasLimit: "100000",    // gas ceiling for destination execution
  };

  const url = `${SOCKET_API_BASE_URL}/v3/swap/quote`;
  const queryParams = new URLSearchParams(quoteParams);
  const response = await fetch(`${url}?${queryParams}`, {
    headers: {
      affiliate: SOCKET_AFFILIATE_ID,
    },
  });
  const data = await response.json();
  const serverReqId = response.headers.get("server-req-id");

  if (!data.success) {
    throw new Error(
      `Quote error: ${data.statusCode}: ${data.message}. server-req-id: ${serverReqId}`
    );
  }
}
```

## Important Notes

* The `destinationPayload` is the `callData` parameter that will be passed to the `executeData` function
* The `receiverAddress` needs to be a contract that implements the `IBungeeExecutor` interface
* Ensure the receiver contract trusts/can handle calls from the Socket executor
* Complex receivers or multi-token logic require higher gas limits
* Execution may fail due to out of gas on destination — increase `destinationGasLimit`
* Re-check `encodeAbiParameters` types match the receiver decode logic to avoid encoding errors

## Complete Examples

<AccordionGroup>
  <Accordion title="Executing a Custom Payload on Destination Using Viem">
    ```javascript theme={null}
    import {
      createWalletClient,
      createPublicClient,
      http,
      encodeAbiParameters,
    } from 'viem';
    import { privateKeyToAccount } from 'viem/accounts';
    import { base } from 'viem/chains';

    const PRIVATE_KEY = process.env.PRIVATE_KEY;
    // Example receiver contract on Base that implements executeData(...)
    // https://basescan.org/address/0xC0b43F2B38CA47CC9e1b9697296716ebCF3D8177#code
    const CONTRACT_ADDRESS = '0xC0b43F2B38CA47CC9e1b9697296716ebCF3D8177';

    const account = privateKeyToAccount(PRIVATE_KEY);

    const publicClient = createPublicClient({ chain: base, transport: http() });
    const walletClient = createWalletClient({ account, chain: base, transport: http() });

    const SOCKET_API_BASE_URL = "https://dedicated-backend.socket.tech";
    const SOCKET_AFFILIATE_ID = "YOUR_AFFILIATE_ID";

    const quoteParams = {
      userOps: "tx",
      userAddress: account.address,
      originChainId: 8453,
      inputToken: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC on Base
      destinationChainId: 8453,
      outputToken: "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2", // USDT on Base
      inputAmount: "3000000", // 3 USDC
    };

    async function main() {
      quoteParams.destinationPayload = encodeAbiParameters(
        [{ type: 'address' }],
        [account.address] // payload: forward funds to this address
      );
      quoteParams.destinationGasLimit = "100000";
      quoteParams.receiverAddress = CONTRACT_ADDRESS;

      const url = `${SOCKET_API_BASE_URL}/v3/swap/quote?${new URLSearchParams(quoteParams)}`;
      const response = await fetch(url, {
        headers: {
          affiliate: SOCKET_AFFILIATE_ID,
        },
      });
      const data = await response.json();

      if (!data.success || !data.result?.routes?.length) {
        throw new Error(`Quote failed: ${data.message}`);
      }

      const route = data.result.routes[0];
      console.log("Quote ID:", route.quoteId);

      // Approve route.approval if present, submit route.txData.object, then poll /v3/swap/status with route.quoteId.
    }

    main();
    ```
  </Accordion>

  <Accordion title="Example Smart Contract Implementation">
    <Warning>
      **For Example Purposes Only**

      The smart contract below is for example purposes only. Please audit your contracts for production usage.
    </Warning>

    ```solidity theme={null}
    // SPDX-License-Identifier: UNLICENSED
    pragma solidity ^0.8.28;

    import {Ownable} from "solady/auth/Ownable.sol";
    import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol";

    interface IBungeeExecutor {
        function executeData(
            bytes32 requestHash,
            uint256[] calldata amounts,
            address[] calldata tokens,
            bytes memory callData
        ) external payable;
    }

    contract ExecuteDestinationPayload is IBungeeExecutor, Ownable {
        address public constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

        event DestinationPayload(
            bytes32 indexed requestHash,
            uint256 amount,
            address indexed token,
            address indexed recipient
        );

        error InvalidArrayLength();
        error ZeroAmount();
        error ZeroAddress();

        constructor() {
            _initializeOwner(msg.sender);
        }

        function executeData(
            bytes32 requestHash,
            uint256[] calldata amounts,
            address[] calldata tokens,
            bytes memory callData
        ) external payable override {
            if (amounts.length != 1 || tokens.length != 1) {
                revert InvalidArrayLength();
            }

            address recipient = abi.decode(callData, (address));
            address token = tokens[0];
            uint256 amount = amounts[0];

            if (token == NATIVE_TOKEN) {
                SafeTransferLib.safeTransferETH(recipient, amount);
            } else {
                SafeTransferLib.safeTransfer(token, recipient, amount);
            }

            emit DestinationPayload(requestHash, amount, token, recipient);
        }

        receive() external payable {}
    }
    ```
  </Accordion>
</AccordionGroup>
