---
title: Transfer Fees
description:
  Create a mint with transfer fees, move withheld fees from token accounts to
  the mint, and withdraw them to a fee receiver token account.
url: /docs/tokens/extensions/transfer-fees
type: tutorial
prerequisites:
  - /docs/tokens/basics/create-mint
  - /docs/tokens/basics/transfer-tokens
related:
  - /docs/tokens/extensions/confidential-transfer
  - /docs/tokens/extensions
---

## What Are Transfer Fees?

The Token Extension Program's _rs`TransferFeeConfig`_ mint extension applies a
fee to each transfer for that mint.

At transfer time:

- The transferred amount is reduced by the configured fee
- The withheld fee is tracked on the destination token account
- Withheld fees can be withdrawn directly from token accounts or harvested to
  the mint
- The `withdraw_withheld_authority` can move harvested fees to a fee receiver
  token account

<Callout type="info" title="Token Account Extensions">
  When a token account is initialized for a mint with _rs`TransferFeeConfig`_,
  the token account is initialized with _rs`TransferFeeAmount`_. When the token
  account is created through the [Associated Token
  Program](/docs/tokens/basics/create-token-account#how-to-create-an-associated-token-account),
  the required account size is calculated and the token account is created with
  the required size and rent-exempt lamports.
</Callout>

## How to Create a Transfer Fee Mint

To create a transfer fee mint:

1. Calculate the mint account size and rent needed for the mint and the
   _rs`TransferFeeConfig`_ extension.
2. Create the mint account with _rs`CreateAccount`_, initialize
   _rs`TransferFeeConfig`_, and initialize the mint with _rs`InitializeMint`_.
3. Create token accounts for the mint. _rs`TransferFeeAmount`_ is automatically
   enabled for token accounts.
4. Use _rs`TransferCheckedWithFee`_ to transfer tokens and verify the expected
   fee. _rs`TransferChecked`_ also works and automatically withholds the
   configured fee on the destination token account.
5. Use _rs`WithdrawWithheldTokensFromAccounts`_ to move withheld fees directly
   from token accounts to a fee receiver token account, signed by the mint's
   `withdraw_withheld_authority`.
6. Use permissionless _rs`HarvestWithheldTokensToMint`_ to move withheld fees
   from token accounts to the mint account, then use
   _rs`WithdrawWithheldTokensFromMint`_ to withdraw the mint account's withheld
   fees to a fee receiver token account, signed by the mint's
   `withdraw_withheld_authority`.
7. Use _rs`SetTransferFee`_ to update the next transfer fee configuration, which
   takes effect starting two epochs later.

<ScrollyCoding>

## !!steps Calculate account size

Calculate the mint account size for the base mint plus the
_rs`TransferFeeConfig`_ extension. This is the size used in _rs`CreateAccount`_.

<CodePlaceholder title="Example" />

```ts !! title="Example"
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();

// !focus(1:14)
const transferFeeConfigExtension = extension("TransferFeeConfig", {
  transferFeeConfigAuthority: client.payer.address,
  withdrawWithheldAuthority: client.payer.address,
  withheldAmount: 0n,
  olderTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  },
  newerTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  }
});

// !focus(1:1)
const mintSpace = BigInt(getMintSize([transferFeeConfigExtension]));
```

## !!steps Calculate rent

Calculate rent using the size needed for the mint plus the
_rs`TransferFeeConfig`_ extension.

<CodePlaceholder title="Example" />

```ts !! title="Example"
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();

const transferFeeConfigExtension = extension("TransferFeeConfig", {
  transferFeeConfigAuthority: client.payer.address,
  withdrawWithheldAuthority: client.payer.address,
  withheldAmount: 0n,
  olderTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  },
  newerTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  }
});

const mintSpace = BigInt(getMintSize([transferFeeConfigExtension]));

// !focus(1:3)
const mintRent = await client.rpc
  .getMinimumBalanceForRentExemption(mintSpace)
  .send();
```

## !!steps Create the mint account

Create the mint account with the calculated space and lamports.

<CodePlaceholder title="Example" />

```ts !! title="Example"
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();

const transferFeeConfigExtension = extension("TransferFeeConfig", {
  transferFeeConfigAuthority: client.payer.address,
  withdrawWithheldAuthority: client.payer.address,
  withheldAmount: 0n,
  olderTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  },
  newerTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  }
});

const mintSpace = BigInt(getMintSize([transferFeeConfigExtension]));

const mintRent = await client.rpc
  .getMinimumBalanceForRentExemption(mintSpace)
  .send();

// !focus(1:9)
await client.sendTransaction([
  getCreateAccountInstruction({
    payer: client.payer,
    newAccount: mint,
    lamports: mintRent,
    space: mintSpace,
    programAddress: TOKEN_2022_PROGRAM_ADDRESS
  })
]);
```

## !!steps Initialize TransferFeeConfig

Initialize the _rs`TransferFeeConfig`_ extension on the mint.

<CodePlaceholder title="Example" />

```ts !! title="Example"
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();

const transferFeeConfigExtension = extension("TransferFeeConfig", {
  transferFeeConfigAuthority: client.payer.address,
  withdrawWithheldAuthority: client.payer.address,
  withheldAmount: 0n,
  olderTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  },
  newerTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  }
});

const mintSpace = BigInt(getMintSize([transferFeeConfigExtension]));

const mintRent = await client.rpc
  .getMinimumBalanceForRentExemption(mintSpace)
  .send();

await client.sendTransaction([
  getCreateAccountInstruction({
    payer: client.payer,
    newAccount: mint,
    lamports: mintRent,
    space: mintSpace,
    programAddress: TOKEN_2022_PROGRAM_ADDRESS
  }),
  // !focus(1:7)
  getInitializeTransferFeeConfigInstruction({
    mint: mint.address,
    transferFeeConfigAuthority: client.payer.address,
    withdrawWithheldAuthority: client.payer.address,
    transferFeeBasisPoints: 150,
    maximumFee: 10n
  })
]);
```

## !!steps Initialize the mint

Initialize the mint with _rs`InitializeMint`_ in the same transaction.

<CodePlaceholder title="Example" />

```ts !! title="Example"
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();

const transferFeeConfigExtension = extension("TransferFeeConfig", {
  transferFeeConfigAuthority: client.payer.address,
  withdrawWithheldAuthority: client.payer.address,
  withheldAmount: 0n,
  olderTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  },
  newerTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  }
});

const mintSpace = BigInt(getMintSize([transferFeeConfigExtension]));

const mintRent = await client.rpc
  .getMinimumBalanceForRentExemption(mintSpace)
  .send();

await client.sendTransaction([
  getCreateAccountInstruction({
    payer: client.payer,
    newAccount: mint,
    lamports: mintRent,
    space: mintSpace,
    programAddress: TOKEN_2022_PROGRAM_ADDRESS
  }),
  getInitializeTransferFeeConfigInstruction({
    mint: mint.address,
    transferFeeConfigAuthority: client.payer.address,
    withdrawWithheldAuthority: client.payer.address,
    transferFeeBasisPoints: 150,
    maximumFee: 10n
  }),
  // !focus(1:6)
  getInitializeMintInstruction({
    mint: mint.address,
    decimals: 2,
    mintAuthority: client.payer.address,
    freezeAuthority: client.payer.address
  })
]);
```

## !!steps Create token accounts and mint tokens

Create token accounts for the source, recipients, and fee receiver, then mint
tokens to the source token account.

<CodePlaceholder title="Example" />

```ts !! title="Example"
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();
const recipientA = await generateKeyPairSigner();
const recipientB = await generateKeyPairSigner();
const feeReceiver = await generateKeyPairSigner();

const transferFeeConfigExtension = extension("TransferFeeConfig", {
  transferFeeConfigAuthority: client.payer.address,
  withdrawWithheldAuthority: client.payer.address,
  withheldAmount: 0n,
  olderTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  },
  newerTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  }
});

const mintSpace = BigInt(getMintSize([transferFeeConfigExtension]));

const mintRent = await client.rpc
  .getMinimumBalanceForRentExemption(mintSpace)
  .send();

await client.sendTransaction([
  getCreateAccountInstruction({
    payer: client.payer,
    newAccount: mint,
    lamports: mintRent,
    space: mintSpace,
    programAddress: TOKEN_2022_PROGRAM_ADDRESS
  }),
  getInitializeTransferFeeConfigInstruction({
    mint: mint.address,
    transferFeeConfigAuthority: client.payer.address,
    withdrawWithheldAuthority: client.payer.address,
    transferFeeBasisPoints: 150,
    maximumFee: 10n
  }),
  getInitializeMintInstruction({
    mint: mint.address,
    decimals: 2,
    mintAuthority: client.payer.address,
    freezeAuthority: client.payer.address
  })
]);

const [sourceToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: client.payer.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [destinationAToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: recipientA.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [destinationBToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: recipientB.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [feeReceiverToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: feeReceiver.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

// !focus(1:29)
await client.sendTransaction([
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: client.payer.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: recipientA.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: recipientB.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: feeReceiver.address
  }),
  getMintToCheckedInstruction({
    mint: mint.address,
    token: sourceToken,
    mintAuthority: client.payer,
    amount: 1_000n,
    decimals: 2
  })
]);
```

## !!steps Transfer with TransferCheckedWithFee

Transfer tokens with _rs`TransferCheckedWithFee`_ and verify the expected fee.

<CodePlaceholder title="Example" />

```ts !! title="Example"
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();
const recipientA = await generateKeyPairSigner();
const recipientB = await generateKeyPairSigner();
const feeReceiver = await generateKeyPairSigner();

const transferFeeConfigExtension = extension("TransferFeeConfig", {
  transferFeeConfigAuthority: client.payer.address,
  withdrawWithheldAuthority: client.payer.address,
  withheldAmount: 0n,
  olderTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  },
  newerTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  }
});

const mintSpace = BigInt(getMintSize([transferFeeConfigExtension]));

const mintRent = await client.rpc
  .getMinimumBalanceForRentExemption(mintSpace)
  .send();

await client.sendTransaction([
  getCreateAccountInstruction({
    payer: client.payer,
    newAccount: mint,
    lamports: mintRent,
    space: mintSpace,
    programAddress: TOKEN_2022_PROGRAM_ADDRESS
  }),
  getInitializeTransferFeeConfigInstruction({
    mint: mint.address,
    transferFeeConfigAuthority: client.payer.address,
    withdrawWithheldAuthority: client.payer.address,
    transferFeeBasisPoints: 150,
    maximumFee: 10n
  }),
  getInitializeMintInstruction({
    mint: mint.address,
    decimals: 2,
    mintAuthority: client.payer.address,
    freezeAuthority: client.payer.address
  })
]);

const [sourceToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: client.payer.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [destinationAToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: recipientA.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [destinationBToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: recipientB.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [feeReceiverToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: feeReceiver.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

await client.sendTransaction([
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: client.payer.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: recipientA.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: recipientB.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: feeReceiver.address
  }),
  getMintToCheckedInstruction({
    mint: mint.address,
    token: sourceToken,
    mintAuthority: client.payer,
    amount: 1_000n,
    decimals: 2
  })
]);

// !focus(1:11)
await client.sendTransaction([
  getTransferCheckedWithFeeInstruction({
    source: sourceToken,
    mint: mint.address,
    destination: destinationAToken,
    authority: client.payer,
    amount: 200n,
    decimals: 2,
    fee: 3n
  })
]);
```

## !!steps Transfer with TransferChecked

Transfer tokens with _rs`TransferChecked`_. The configured fee is still withheld
on the destination token account.

<CodePlaceholder title="Example" />

```ts !! title="Example"
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();
const recipientA = await generateKeyPairSigner();
const recipientB = await generateKeyPairSigner();
const feeReceiver = await generateKeyPairSigner();

const transferFeeConfigExtension = extension("TransferFeeConfig", {
  transferFeeConfigAuthority: client.payer.address,
  withdrawWithheldAuthority: client.payer.address,
  withheldAmount: 0n,
  olderTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  },
  newerTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  }
});

const mintSpace = BigInt(getMintSize([transferFeeConfigExtension]));

const mintRent = await client.rpc
  .getMinimumBalanceForRentExemption(mintSpace)
  .send();

await client.sendTransaction([
  getCreateAccountInstruction({
    payer: client.payer,
    newAccount: mint,
    lamports: mintRent,
    space: mintSpace,
    programAddress: TOKEN_2022_PROGRAM_ADDRESS
  }),
  getInitializeTransferFeeConfigInstruction({
    mint: mint.address,
    transferFeeConfigAuthority: client.payer.address,
    withdrawWithheldAuthority: client.payer.address,
    transferFeeBasisPoints: 150,
    maximumFee: 10n
  }),
  getInitializeMintInstruction({
    mint: mint.address,
    decimals: 2,
    mintAuthority: client.payer.address,
    freezeAuthority: client.payer.address
  })
]);

const [sourceToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: client.payer.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [destinationAToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: recipientA.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [destinationBToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: recipientB.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [feeReceiverToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: feeReceiver.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

await client.sendTransaction([
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: client.payer.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: recipientA.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: recipientB.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: feeReceiver.address
  }),
  getMintToCheckedInstruction({
    mint: mint.address,
    token: sourceToken,
    mintAuthority: client.payer,
    amount: 1_000n,
    decimals: 2
  })
]);

await client.sendTransaction([
  getTransferCheckedWithFeeInstruction({
    source: sourceToken,
    mint: mint.address,
    destination: destinationAToken,
    authority: client.payer,
    amount: 200n,
    decimals: 2,
    fee: 3n
  })
]);

// !focus(1:10)
await client.sendTransaction([
  getTransferCheckedInstruction({
    source: sourceToken,
    mint: mint.address,
    destination: destinationBToken,
    authority: client.payer,
    amount: 200n,
    decimals: 2
  })
]);
```

## !!steps Withdraw withheld fees from token accounts

Use _rs`WithdrawWithheldTokensFromAccounts`_ to move withheld fees directly from
token accounts to the fee receiver token account.

<CodePlaceholder title="Example" />

```ts !! title="Example"
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();
const recipientA = await generateKeyPairSigner();
const recipientB = await generateKeyPairSigner();
const feeReceiver = await generateKeyPairSigner();

const transferFeeConfigExtension = extension("TransferFeeConfig", {
  transferFeeConfigAuthority: client.payer.address,
  withdrawWithheldAuthority: client.payer.address,
  withheldAmount: 0n,
  olderTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  },
  newerTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  }
});

const mintSpace = BigInt(getMintSize([transferFeeConfigExtension]));

const mintRent = await client.rpc
  .getMinimumBalanceForRentExemption(mintSpace)
  .send();

await client.sendTransaction([
  getCreateAccountInstruction({
    payer: client.payer,
    newAccount: mint,
    lamports: mintRent,
    space: mintSpace,
    programAddress: TOKEN_2022_PROGRAM_ADDRESS
  }),
  getInitializeTransferFeeConfigInstruction({
    mint: mint.address,
    transferFeeConfigAuthority: client.payer.address,
    withdrawWithheldAuthority: client.payer.address,
    transferFeeBasisPoints: 150,
    maximumFee: 10n
  }),
  getInitializeMintInstruction({
    mint: mint.address,
    decimals: 2,
    mintAuthority: client.payer.address,
    freezeAuthority: client.payer.address
  })
]);

const [sourceToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: client.payer.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [destinationAToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: recipientA.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [destinationBToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: recipientB.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [feeReceiverToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: feeReceiver.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

await client.sendTransaction([
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: client.payer.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: recipientA.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: recipientB.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: feeReceiver.address
  }),
  getMintToCheckedInstruction({
    mint: mint.address,
    token: sourceToken,
    mintAuthority: client.payer,
    amount: 1_000n,
    decimals: 2
  })
]);

await client.sendTransaction([
  getTransferCheckedWithFeeInstruction({
    source: sourceToken,
    mint: mint.address,
    destination: destinationAToken,
    authority: client.payer,
    amount: 200n,
    decimals: 2,
    fee: 3n
  })
]);

await client.sendTransaction([
  getTransferCheckedInstruction({
    source: sourceToken,
    mint: mint.address,
    destination: destinationBToken,
    authority: client.payer,
    amount: 200n,
    decimals: 2
  })
]);

// !focus(1:9)
await client.sendTransaction([
  getWithdrawWithheldTokensFromAccountsInstruction({
    mint: mint.address,
    feeReceiver: feeReceiverToken,
    withdrawWithheldAuthority: client.payer,
    numTokenAccounts: 1,
    sources: [destinationAToken]
  })
]);
```

## !!steps Harvest withheld fees to the mint

Use _rs`HarvestWithheldTokensToMint`_ to move withheld fees from token accounts
to the mint account's withheld accumulator.

<CodePlaceholder title="Example" />

```ts !! title="Example"
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();
const recipientA = await generateKeyPairSigner();
const recipientB = await generateKeyPairSigner();
const feeReceiver = await generateKeyPairSigner();

const transferFeeConfigExtension = extension("TransferFeeConfig", {
  transferFeeConfigAuthority: client.payer.address,
  withdrawWithheldAuthority: client.payer.address,
  withheldAmount: 0n,
  olderTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  },
  newerTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  }
});

const mintSpace = BigInt(getMintSize([transferFeeConfigExtension]));

const mintRent = await client.rpc
  .getMinimumBalanceForRentExemption(mintSpace)
  .send();

await client.sendTransaction([
  getCreateAccountInstruction({
    payer: client.payer,
    newAccount: mint,
    lamports: mintRent,
    space: mintSpace,
    programAddress: TOKEN_2022_PROGRAM_ADDRESS
  }),
  getInitializeTransferFeeConfigInstruction({
    mint: mint.address,
    transferFeeConfigAuthority: client.payer.address,
    withdrawWithheldAuthority: client.payer.address,
    transferFeeBasisPoints: 150,
    maximumFee: 10n
  }),
  getInitializeMintInstruction({
    mint: mint.address,
    decimals: 2,
    mintAuthority: client.payer.address,
    freezeAuthority: client.payer.address
  })
]);

const [sourceToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: client.payer.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [destinationAToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: recipientA.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [destinationBToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: recipientB.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [feeReceiverToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: feeReceiver.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

await client.sendTransaction([
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: client.payer.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: recipientA.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: recipientB.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: feeReceiver.address
  }),
  getMintToCheckedInstruction({
    mint: mint.address,
    token: sourceToken,
    mintAuthority: client.payer,
    amount: 1_000n,
    decimals: 2
  })
]);

await client.sendTransaction([
  getTransferCheckedWithFeeInstruction({
    source: sourceToken,
    mint: mint.address,
    destination: destinationAToken,
    authority: client.payer,
    amount: 200n,
    decimals: 2,
    fee: 3n
  })
]);

await client.sendTransaction([
  getTransferCheckedInstruction({
    source: sourceToken,
    mint: mint.address,
    destination: destinationBToken,
    authority: client.payer,
    amount: 200n,
    decimals: 2
  })
]);

await client.sendTransaction([
  getWithdrawWithheldTokensFromAccountsInstruction({
    mint: mint.address,
    feeReceiver: feeReceiverToken,
    withdrawWithheldAuthority: client.payer,
    numTokenAccounts: 1,
    sources: [destinationAToken]
  })
]);

// !focus(1:6)
await client.sendTransaction([
  getHarvestWithheldTokensToMintInstruction({
    mint: mint.address,
    sources: [destinationBToken]
  })
]);
```

## !!steps Withdraw withheld fees from the mint

Use _rs`WithdrawWithheldTokensFromMint`_ to move harvested fees from the mint
account to the fee receiver token account.

<CodePlaceholder title="Example" />

```ts !! title="Example"
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();
const recipientA = await generateKeyPairSigner();
const recipientB = await generateKeyPairSigner();
const feeReceiver = await generateKeyPairSigner();

const transferFeeConfigExtension = extension("TransferFeeConfig", {
  transferFeeConfigAuthority: client.payer.address,
  withdrawWithheldAuthority: client.payer.address,
  withheldAmount: 0n,
  olderTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  },
  newerTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  }
});

const mintSpace = BigInt(getMintSize([transferFeeConfigExtension]));

const mintRent = await client.rpc
  .getMinimumBalanceForRentExemption(mintSpace)
  .send();

await client.sendTransaction([
  getCreateAccountInstruction({
    payer: client.payer,
    newAccount: mint,
    lamports: mintRent,
    space: mintSpace,
    programAddress: TOKEN_2022_PROGRAM_ADDRESS
  }),
  getInitializeTransferFeeConfigInstruction({
    mint: mint.address,
    transferFeeConfigAuthority: client.payer.address,
    withdrawWithheldAuthority: client.payer.address,
    transferFeeBasisPoints: 150,
    maximumFee: 10n
  }),
  getInitializeMintInstruction({
    mint: mint.address,
    decimals: 2,
    mintAuthority: client.payer.address,
    freezeAuthority: client.payer.address
  })
]);

const [sourceToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: client.payer.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [destinationAToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: recipientA.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [destinationBToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: recipientB.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [feeReceiverToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: feeReceiver.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

await client.sendTransaction([
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: client.payer.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: recipientA.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: recipientB.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: feeReceiver.address
  }),
  getMintToCheckedInstruction({
    mint: mint.address,
    token: sourceToken,
    mintAuthority: client.payer,
    amount: 1_000n,
    decimals: 2
  })
]);

await client.sendTransaction([
  getTransferCheckedWithFeeInstruction({
    source: sourceToken,
    mint: mint.address,
    destination: destinationAToken,
    authority: client.payer,
    amount: 200n,
    decimals: 2,
    fee: 3n
  })
]);

await client.sendTransaction([
  getTransferCheckedInstruction({
    source: sourceToken,
    mint: mint.address,
    destination: destinationBToken,
    authority: client.payer,
    amount: 200n,
    decimals: 2
  })
]);

await client.sendTransaction([
  getWithdrawWithheldTokensFromAccountsInstruction({
    mint: mint.address,
    feeReceiver: feeReceiverToken,
    withdrawWithheldAuthority: client.payer,
    numTokenAccounts: 1,
    sources: [destinationAToken]
  })
]);

await client.sendTransaction([
  getHarvestWithheldTokensToMintInstruction({
    mint: mint.address,
    sources: [destinationBToken]
  })
]);

// !focus(1:7)
await client.sendTransaction([
  getWithdrawWithheldTokensFromMintInstruction({
    mint: mint.address,
    feeReceiver: feeReceiverToken,
    withdrawWithheldAuthority: client.payer
  })
]);
```

## !!steps Update the next transfer fee

Use _rs`SetTransferFee`_ to update the next transfer fee configuration.

<CodePlaceholder title="Example" />

```ts !! title="Example"
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();
const recipientA = await generateKeyPairSigner();
const recipientB = await generateKeyPairSigner();
const feeReceiver = await generateKeyPairSigner();

const transferFeeConfigExtension = extension("TransferFeeConfig", {
  transferFeeConfigAuthority: client.payer.address,
  withdrawWithheldAuthority: client.payer.address,
  withheldAmount: 0n,
  olderTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  },
  newerTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  }
});

const mintSpace = BigInt(getMintSize([transferFeeConfigExtension]));

const mintRent = await client.rpc
  .getMinimumBalanceForRentExemption(mintSpace)
  .send();

await client.sendTransaction([
  getCreateAccountInstruction({
    payer: client.payer,
    newAccount: mint,
    lamports: mintRent,
    space: mintSpace,
    programAddress: TOKEN_2022_PROGRAM_ADDRESS
  }),
  getInitializeTransferFeeConfigInstruction({
    mint: mint.address,
    transferFeeConfigAuthority: client.payer.address,
    withdrawWithheldAuthority: client.payer.address,
    transferFeeBasisPoints: 150,
    maximumFee: 10n
  }),
  getInitializeMintInstruction({
    mint: mint.address,
    decimals: 2,
    mintAuthority: client.payer.address,
    freezeAuthority: client.payer.address
  })
]);

const [sourceToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: client.payer.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [destinationAToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: recipientA.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [destinationBToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: recipientB.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [feeReceiverToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: feeReceiver.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

await client.sendTransaction([
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: client.payer.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: recipientA.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: recipientB.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: feeReceiver.address
  }),
  getMintToCheckedInstruction({
    mint: mint.address,
    token: sourceToken,
    mintAuthority: client.payer,
    amount: 1_000n,
    decimals: 2
  })
]);

await client.sendTransaction([
  getTransferCheckedWithFeeInstruction({
    source: sourceToken,
    mint: mint.address,
    destination: destinationAToken,
    authority: client.payer,
    amount: 200n,
    decimals: 2,
    fee: 3n
  })
]);

await client.sendTransaction([
  getTransferCheckedInstruction({
    source: sourceToken,
    mint: mint.address,
    destination: destinationBToken,
    authority: client.payer,
    amount: 200n,
    decimals: 2
  })
]);

await client.sendTransaction([
  getWithdrawWithheldTokensFromAccountsInstruction({
    mint: mint.address,
    feeReceiver: feeReceiverToken,
    withdrawWithheldAuthority: client.payer,
    numTokenAccounts: 1,
    sources: [destinationAToken]
  })
]);

await client.sendTransaction([
  getHarvestWithheldTokensToMintInstruction({
    mint: mint.address,
    sources: [destinationBToken]
  })
]);

await client.sendTransaction([
  getWithdrawWithheldTokensFromMintInstruction({
    mint: mint.address,
    feeReceiver: feeReceiverToken,
    withdrawWithheldAuthority: client.payer
  })
]);

// !focus(1:8)
await client.sendTransaction([
  getSetTransferFeeInstruction({
    mint: mint.address,
    transferFeeConfigAuthority: client.payer,
    transferFeeBasisPoints: 250,
    maximumFee: 25n
  })
]);
```

</ScrollyCoding>

<Callout type="info" title="Instruction Order">
  _rs`InitializeTransferFeeConfig`_ must come before _rs`InitializeMint`_.
  _rs`CreateAccount`_, _rs`InitializeTransferFeeConfig`_, and
  _rs`InitializeMint`_ must be included in the same transaction.
</Callout>

### Source Reference

| Item                                                             | Description                                                                                                                                                                                         | Source                                                                                                                                      |
| ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| _rs`TransferFeeConfig`_                                          | Mint extension that stores the fee authorities, accumulated withheld amount, and the older and newer transfer fee configurations.                                                                   | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/interface/src/extension/transfer_fee/mod.rs#L128-L145)         |
| _rs`TransferFee`_                                                | Fee configuration struct stored in _rs`TransferFeeConfig`_ that defines the epoch when the fee takes effect, the maximum fee, and the fee in basis points.                                          | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/interface/src/extension/transfer_fee/mod.rs#L32-L40)           |
| _rs`TransferFeeAmount`_                                          | Token account extension that stores the amount withheld during transfers for a token account.                                                                                                       | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/interface/src/extension/transfer_fee/mod.rs#L169-L177)         |
| _rs`TransferFeeInstruction::InitializeTransferFeeConfig`_        | Instruction that initializes transfer-fee settings before _rs`InitializeMint`_.                                                                                                                     | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/interface/src/extension/transfer_fee/instruction.rs#L24-L48)   |
| _rs`TransferFeeInstruction::TransferCheckedWithFee`_             | Transfer instruction that verifies the caller-supplied fee matches the mint's current transfer-fee config.                                                                                          | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/interface/src/extension/transfer_fee/instruction.rs#L49-L80)   |
| _rs`TransferFeeInstruction::WithdrawWithheldTokensFromAccounts`_ | Instruction that moves withheld fees directly from token accounts to a fee receiver token account, signed by the mint's `withdraw_withheld_authority`.                                              | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/interface/src/extension/transfer_fee/instruction.rs#L99-L122)  |
| _rs`TransferFeeInstruction::HarvestWithheldTokensToMint`_        | Permissionless instruction that moves withheld fees from token accounts to the mint account's withheld accumulator.                                                                                 | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/interface/src/extension/transfer_fee/instruction.rs#L123-L134) |
| _rs`TransferFeeInstruction::WithdrawWithheldTokensFromMint`_     | Instruction that withdraws the mint account's withheld fees to a fee receiver token account, signed by the mint's `withdraw_withheld_authority`.                                                    | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/interface/src/extension/transfer_fee/instruction.rs#L81-L98)   |
| _rs`TransferFeeInstruction::SetTransferFee`_                     | Instruction that updates the newer transfer fee configuration, which takes effect starting two epochs later.                                                                                        | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/interface/src/extension/transfer_fee/instruction.rs#L135-L154) |
| _rs`process_initialize_transfer_fee_config`_                     | Processor logic that initializes the _rs`TransferFeeConfig`_ extension on an uninitialized mint and sets both the older and newer transfer fee configurations to the initial fee.                   | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/program/src/extension/transfer_fee/processor.rs#L26-L58)       |
| _rs`process_withdraw_withheld_tokens_from_accounts`_             | Processor logic that validates `withdraw_withheld_authority` and moves withheld fees from token accounts to a destination token account.                                                            | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/program/src/extension/transfer_fee/processor.rs#L208-L278)     |
| _rs`process_harvest_withheld_tokens_to_mint`_                    | Processor logic that harvests withheld fees from token accounts to the mint account's withheld accumulator.                                                                                         | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/program/src/extension/transfer_fee/processor.rs#L181-L206)     |
| _rs`process_withdraw_withheld_tokens_from_mint`_                 | Processor logic that validates `withdraw_withheld_authority` and moves the mint account's withheld amount to a destination token account.                                                           | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/program/src/extension/transfer_fee/processor.rs#L114-L158)     |
| _rs`process_set_transfer_fee`_                                   | Processor logic that validates the transfer-fee config authority and updates the newer transfer fee configuration to take effect starting two epochs later.                                         | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/program/src/extension/transfer_fee/processor.rs#L61-L112)      |
| _rs`get_required_init_account_extensions`_                       | Used to automatically add token account extensions when token accounts are initialized based on extensions enabled on the mint. For _rs`TransferFeeConfig`_ mints, it adds _rs`TransferFeeAmount`_. | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/interface/src/extension/mod.rs#L1301-L1303)                    |

### Typescript

The `Kit` example below uses explicit Token-2022 instructions. Legacy examples
using `@solana/web3.js` and `@solana/spl-token` are included for reference.

#### Kit

<CodeTabs storage="token-ts-kit" flags="r">

```ts !! title="Instructions"
import {
  lamports,
  createClient,
  generateKeyPairSigner,
  unwrapOption
} from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getCreateAccountInstruction } from "@solana-program/system";
import {
  extension,
  fetchMint,
  fetchToken,
  findAssociatedTokenPda,
  getCreateAssociatedTokenInstructionAsync,
  getHarvestWithheldTokensToMintInstruction,
  getInitializeMintInstruction,
  getInitializeTransferFeeConfigInstruction,
  getMintSize,
  getMintToCheckedInstruction,
  getSetTransferFeeInstruction,
  getTransferCheckedWithFeeInstruction,
  getWithdrawWithheldTokensFromAccountsInstruction,
  getWithdrawWithheldTokensFromMintInstruction,
  isExtension,
  TOKEN_2022_PROGRAM_ADDRESS
} from "@solana-program/token-2022";

const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();
const recipientA = await generateKeyPairSigner();
const recipientB = await generateKeyPairSigner();
const feeReceiver = await generateKeyPairSigner();

const transferFeeConfigExtension = extension("TransferFeeConfig", {
  transferFeeConfigAuthority: client.payer.address,
  withdrawWithheldAuthority: client.payer.address,
  withheldAmount: 0n,
  olderTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  },
  newerTransferFee: {
    epoch: 0n,
    maximumFee: 10n,
    transferFeeBasisPoints: 150
  }
});
const mintSpace = BigInt(getMintSize([transferFeeConfigExtension]));
const mintRent = await client.rpc
  .getMinimumBalanceForRentExemption(mintSpace)
  .send();

await client.sendTransaction([
  getCreateAccountInstruction({
    payer: client.payer, // Account funding account creation.
    newAccount: mint, // New mint account to create.
    lamports: mintRent, // Lamports funding the mint account rent.
    space: mintSpace, // Account size in bytes for the mint plus TransferFeeConfig.
    programAddress: TOKEN_2022_PROGRAM_ADDRESS // Program that owns the mint account.
  }),
  // !mark(1:7)
  getInitializeTransferFeeConfigInstruction({
    mint: mint.address, // Mint account that stores the TransferFeeConfig extension.
    transferFeeConfigAuthority: client.payer.address, // Authority allowed to update the transfer fee later.
    withdrawWithheldAuthority: client.payer.address, // Value stored in the mint's `withdraw_withheld_authority` field.
    transferFeeBasisPoints: 150, // Transfer fee in basis points.
    maximumFee: 10n // Maximum fee charged on each transfer.
  }),
  getInitializeMintInstruction({
    mint: mint.address, // Mint account to initialize.
    decimals: 2, // Number of decimals for the token.
    mintAuthority: client.payer.address, // Authority allowed to mint new tokens.
    freezeAuthority: client.payer.address // Authority allowed to freeze token accounts.
  })
]);

const [sourceToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: client.payer.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [destinationAToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: recipientA.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [destinationBToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: recipientB.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [feeReceiverToken] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: feeReceiver.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

await client.sendTransaction([
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: client.payer.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: recipientA.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: recipientB.address
  }),
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: feeReceiver.address
  }),
  getMintToCheckedInstruction({
    mint: mint.address,
    token: sourceToken,
    mintAuthority: client.payer,
    amount: 1_000n,
    decimals: 2
  })
]);

await client.sendTransaction([
  // !mark(1:8)
  getTransferCheckedWithFeeInstruction({
    source: sourceToken, // Token account sending the transfer.
    mint: mint.address, // Mint with the transfer fee configuration.
    destination: destinationAToken, // Token account receiving the transfer.
    authority: client.payer, // Signer approving the transfer.
    amount: 200n, // Token amount in base units.
    decimals: 2, // Decimals defined on the mint.
    fee: 3n // Expected transfer fee for this transfer.
  })
]);

await client.sendTransaction([
  // !mark(1:7)
  getWithdrawWithheldTokensFromAccountsInstruction({
    mint: mint.address, // Mint with the transfer fee configuration.
    feeReceiver: feeReceiverToken, // Token account receiving the withdrawn fees.
    withdrawWithheldAuthority: client.payer, // Signer matching the mint's `withdraw_withheld_authority`.
    numTokenAccounts: 1, // Number of token accounts listed in `sources`.
    sources: [destinationAToken] // Token accounts to withdraw withheld fees from.
  })
]);

await client.sendTransaction([
  // !mark(1:8)
  getTransferCheckedWithFeeInstruction({
    source: sourceToken, // Token account sending the transfer.
    mint: mint.address, // Mint with the transfer fee configuration.
    destination: destinationBToken, // Token account receiving the transfer.
    authority: client.payer, // Signer approving the transfer.
    amount: 200n, // Token amount in base units.
    decimals: 2, // Decimals defined on the mint.
    fee: 3n // Expected transfer fee for this transfer.
  })
]);

await client.sendTransaction([
  // !mark(1:4)
  getHarvestWithheldTokensToMintInstruction({
    mint: mint.address, // Mint that collects harvested withheld fees.
    sources: [destinationBToken] // Token accounts to harvest withheld fees from.
  })
]);

await client.sendTransaction([
  // !mark(1:5)
  getWithdrawWithheldTokensFromMintInstruction({
    mint: mint.address, // Mint storing harvested withheld fees.
    feeReceiver: feeReceiverToken, // Token account receiving withdrawn fees.
    withdrawWithheldAuthority: client.payer // Signer matching the mint's `withdraw_withheld_authority`.
  }),
  // !mark(1:6)
  getSetTransferFeeInstruction({
    mint: mint.address, // Mint whose next transfer fee configuration is updated.
    transferFeeConfigAuthority: client.payer, // Signer authorized to update the transfer fee later.
    transferFeeBasisPoints: 250, // New transfer fee in basis points.
    maximumFee: 25n // New maximum fee for the next transfer fee configuration.
  })
]);

const destinationAAccount = await fetchToken(client.rpc, destinationAToken);
const destinationBAccount = await fetchToken(client.rpc, destinationBToken);
const feeReceiverAccount = await fetchToken(client.rpc, feeReceiverToken);
const mintAccount = await fetchMint(client.rpc, mint.address);
const transferFeeConfig = (
  unwrapOption(mintAccount.data.extensions) ?? []
).find((item) => isExtension("TransferFeeConfig", item));

console.log("Mint Address:", mint.address);
console.dir(
  {
    destinationA: {
      amount: destinationAAccount.data.amount,
      extensions: destinationAAccount.data.extensions
    },
    destinationB: {
      amount: destinationBAccount.data.amount,
      extensions: destinationBAccount.data.extensions
    },
    feeReceiver: {
      amount: feeReceiverAccount.data.amount,
      extensions: feeReceiverAccount.data.extensions
    },
    transferFeeConfig
  },
  { depth: null }
);
```

</CodeTabs>

#### Web3.js

<CodeTabs storage="token-ts-legacy" flags="r">

```ts !! title="Instructions"
import {
  Connection,
  Keypair,
  LAMPORTS_PER_SOL,
  sendAndConfirmTransaction,
  SystemProgram,
  Transaction
} from "@solana/web3.js";
import {
  ASSOCIATED_TOKEN_PROGRAM_ID,
  ExtensionType,
  createAssociatedTokenAccountInstruction,
  createHarvestWithheldTokensToMintInstruction,
  createInitializeMintInstruction,
  createInitializeTransferFeeConfigInstruction,
  createMintToCheckedInstruction,
  createSetTransferFeeInstruction,
  createTransferCheckedWithFeeInstruction,
  createWithdrawWithheldTokensFromAccountsInstruction,
  createWithdrawWithheldTokensFromMintInstruction,
  getAccount,
  getAssociatedTokenAddressSync,
  getMint,
  getMintLen,
  getTransferFeeAmount,
  getTransferFeeConfig,
  TOKEN_2022_PROGRAM_ID
} from "@solana/spl-token";

const connection = new Connection("http://localhost:8899", "confirmed");
const latestBlockhash = await connection.getLatestBlockhash();

const feePayer = Keypair.generate();
const recipientA = Keypair.generate();
const recipientB = Keypair.generate();
const feeReceiver = Keypair.generate();
const airdropSignature = await connection.requestAirdrop(
  feePayer.publicKey,
  5 * LAMPORTS_PER_SOL
);
await connection.confirmTransaction({
  blockhash: latestBlockhash.blockhash,
  lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
  signature: airdropSignature
});

const mint = Keypair.generate();
const transferFeeConfigExtensions = [ExtensionType.TransferFeeConfig];
const mintLen = getMintLen(transferFeeConfigExtensions);
const mintRent = await connection.getMinimumBalanceForRentExemption(mintLen);

const sourceToken = getAssociatedTokenAddressSync(
  mint.publicKey,
  feePayer.publicKey,
  false,
  TOKEN_2022_PROGRAM_ID,
  ASSOCIATED_TOKEN_PROGRAM_ID
);

const destinationAToken = getAssociatedTokenAddressSync(
  mint.publicKey,
  recipientA.publicKey,
  false,
  TOKEN_2022_PROGRAM_ID,
  ASSOCIATED_TOKEN_PROGRAM_ID
);

const destinationBToken = getAssociatedTokenAddressSync(
  mint.publicKey,
  recipientB.publicKey,
  false,
  TOKEN_2022_PROGRAM_ID,
  ASSOCIATED_TOKEN_PROGRAM_ID
);

const feeReceiverToken = getAssociatedTokenAddressSync(
  mint.publicKey,
  feeReceiver.publicKey,
  false,
  TOKEN_2022_PROGRAM_ID,
  ASSOCIATED_TOKEN_PROGRAM_ID
);

await sendAndConfirmTransaction(
  connection,
  new Transaction().add(
    SystemProgram.createAccount({
      fromPubkey: feePayer.publicKey, // Account funding account creation.
      newAccountPubkey: mint.publicKey, // New mint account to create.
      lamports: mintRent, // Lamports funding the mint account rent.
      space: mintLen, // Account size in bytes for the mint plus TransferFeeConfig.
      programId: TOKEN_2022_PROGRAM_ID // Program that owns the mint account.
    }),
    // !mark(1:8)
    createInitializeTransferFeeConfigInstruction(
      mint.publicKey, // Mint account that stores the TransferFeeConfig extension.
      feePayer.publicKey, // Authority allowed to update the transfer fee later.
      feePayer.publicKey, // Value stored in the mint's `withdraw_withheld_authority` field.
      150, // Transfer fee in basis points.
      10n, // Maximum fee charged on each transfer.
      TOKEN_2022_PROGRAM_ID // Token program that owns the mint.
    ),
    createInitializeMintInstruction(
      mint.publicKey, // Mint account to initialize.
      2, // Number of decimals for the token.
      feePayer.publicKey, // Authority allowed to mint new tokens.
      feePayer.publicKey, // Authority allowed to freeze token accounts.
      TOKEN_2022_PROGRAM_ID // Program that owns the mint account.
    )
  ),
  [feePayer, mint],
  { commitment: "confirmed" }
);

await sendAndConfirmTransaction(
  connection,
  new Transaction().add(
    createAssociatedTokenAccountInstruction(
      feePayer.publicKey,
      sourceToken,
      feePayer.publicKey,
      mint.publicKey,
      TOKEN_2022_PROGRAM_ID,
      ASSOCIATED_TOKEN_PROGRAM_ID
    ),
    createAssociatedTokenAccountInstruction(
      feePayer.publicKey,
      destinationAToken,
      recipientA.publicKey,
      mint.publicKey,
      TOKEN_2022_PROGRAM_ID,
      ASSOCIATED_TOKEN_PROGRAM_ID
    ),
    createAssociatedTokenAccountInstruction(
      feePayer.publicKey,
      destinationBToken,
      recipientB.publicKey,
      mint.publicKey,
      TOKEN_2022_PROGRAM_ID,
      ASSOCIATED_TOKEN_PROGRAM_ID
    ),
    createAssociatedTokenAccountInstruction(
      feePayer.publicKey,
      feeReceiverToken,
      feeReceiver.publicKey,
      mint.publicKey,
      TOKEN_2022_PROGRAM_ID,
      ASSOCIATED_TOKEN_PROGRAM_ID
    ),
    createMintToCheckedInstruction(
      mint.publicKey,
      sourceToken,
      feePayer.publicKey,
      1_000,
      2,
      [],
      TOKEN_2022_PROGRAM_ID
    )
  ),
  [feePayer],
  { commitment: "confirmed" }
);

await sendAndConfirmTransaction(
  connection,
  new Transaction().add(
    // !mark(1:11)
    createTransferCheckedWithFeeInstruction(
      sourceToken, // Token account sending the transfer.
      mint.publicKey, // Mint with the transfer fee configuration.
      destinationAToken, // Token account receiving the transfer.
      feePayer.publicKey, // Signer approving the transfer.
      200n, // Token amount in base units.
      2, // Decimals defined on the mint.
      3n, // Expected transfer fee for this transfer.
      [], // Additional multisig signers.
      TOKEN_2022_PROGRAM_ID // Token program that processes the transfer.
    )
  ),
  [feePayer],
  { commitment: "confirmed" }
);

await sendAndConfirmTransaction(
  connection,
  new Transaction().add(
    // !mark(1:8)
    createWithdrawWithheldTokensFromAccountsInstruction(
      mint.publicKey, // Mint with the transfer fee configuration.
      feeReceiverToken, // Token account receiving the withdrawn fees.
      feePayer.publicKey, // Signer matching the mint's `withdraw_withheld_authority`.
      [], // Additional multisig signers.
      [destinationAToken], // Token accounts to withdraw withheld fees from.
      TOKEN_2022_PROGRAM_ID // Token program that processes the withdraw.
    )
  ),
  [feePayer],
  { commitment: "confirmed" }
);

await sendAndConfirmTransaction(
  connection,
  new Transaction().add(
    // !mark(1:11)
    createTransferCheckedWithFeeInstruction(
      sourceToken, // Token account sending the transfer.
      mint.publicKey, // Mint with the transfer fee configuration.
      destinationBToken, // Token account receiving the transfer.
      feePayer.publicKey, // Signer approving the transfer.
      200n, // Token amount in base units.
      2, // Decimals defined on the mint.
      3n, // Expected transfer fee for this transfer.
      [], // Additional multisig signers.
      TOKEN_2022_PROGRAM_ID // Token program that processes the transfer.
    )
  ),
  [feePayer],
  { commitment: "confirmed" }
);

await sendAndConfirmTransaction(
  connection,
  new Transaction().add(
    // !mark(1:5)
    createHarvestWithheldTokensToMintInstruction(
      mint.publicKey, // Mint that collects harvested withheld fees.
      [destinationBToken], // Token accounts to harvest withheld fees from.
      TOKEN_2022_PROGRAM_ID // Token program that processes the harvest.
    )
  ),
  [feePayer],
  { commitment: "confirmed" }
);

await sendAndConfirmTransaction(
  connection,
  new Transaction().add(
    // !mark(1:7)
    createWithdrawWithheldTokensFromMintInstruction(
      mint.publicKey, // Mint storing harvested withheld fees.
      feeReceiverToken, // Token account receiving withdrawn fees.
      feePayer.publicKey, // Signer matching the mint's `withdraw_withheld_authority`.
      [], // Additional multisig signers.
      TOKEN_2022_PROGRAM_ID // Token program that processes the withdraw.
    ),
    // !mark(1:8)
    createSetTransferFeeInstruction(
      mint.publicKey, // Mint whose next transfer fee configuration is updated.
      feePayer.publicKey, // Authority allowed to update the transfer fee later.
      [], // Additional multisig signers.
      250, // New transfer fee in basis points.
      25n, // New maximum fee for the next transfer fee configuration.
      TOKEN_2022_PROGRAM_ID // Token program that owns the mint.
    )
  ),
  [feePayer],
  { commitment: "confirmed" }
);

const destinationAAccount = await getAccount(
  connection,
  destinationAToken,
  "confirmed",
  TOKEN_2022_PROGRAM_ID
);
const destinationBAccount = await getAccount(
  connection,
  destinationBToken,
  "confirmed",
  TOKEN_2022_PROGRAM_ID
);
const feeReceiverAccount = await getAccount(
  connection,
  feeReceiverToken,
  "confirmed",
  TOKEN_2022_PROGRAM_ID
);
const mintAccount = await getMint(
  connection,
  mint.publicKey,
  "confirmed",
  TOKEN_2022_PROGRAM_ID
);

console.log("Mint Address:", mint.publicKey.toBase58());
console.log("Destination A Amount:", destinationAAccount.amount.toString());
console.log(
  "Destination A Transfer Fee Amount:",
  getTransferFeeAmount(destinationAAccount)
);
console.log("Destination B Amount:", destinationBAccount.amount.toString());
console.log(
  "Destination B Transfer Fee Amount:",
  getTransferFeeAmount(destinationBAccount)
);
console.log("Fee Receiver Amount:", feeReceiverAccount.amount.toString());
console.log(
  "Fee Receiver Transfer Fee Amount:",
  getTransferFeeAmount(feeReceiverAccount)
);
console.log("Transfer Fee Config:", getTransferFeeConfig(mintAccount));
```

</CodeTabs>

### Rust

<CodeTabs storage="token-rs" flags="r">

```rust !! title="Rust"
use anyhow::Result;
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_commitment_config::CommitmentConfig;
use solana_sdk::{
    signature::{Keypair, Signer},
    transaction::Transaction,
};
use solana_system_interface::instruction::create_account;
use spl_associated_token_account_interface::{
    address::get_associated_token_address_with_program_id,
    instruction::create_associated_token_account,
};
use spl_token_2022_interface::{
    extension::{
        transfer_fee::{
            instruction::{
                harvest_withheld_tokens_to_mint, initialize_transfer_fee_config,
                set_transfer_fee, transfer_checked_with_fee,
                withdraw_withheld_tokens_from_accounts, withdraw_withheld_tokens_from_mint,
            },
            TransferFeeAmount, TransferFeeConfig,
        },
        BaseStateWithExtensions, ExtensionType, StateWithExtensions,
    },
    instruction::{initialize_mint, mint_to_checked},
    state::{Account, Mint},
    ID as TOKEN_2022_PROGRAM_ID,
};

#[tokio::main]
async fn main() -> Result<()> {
    let client = RpcClient::new_with_commitment(
        String::from("http://localhost:8899"),
        CommitmentConfig::confirmed(),
    );
    let fee_payer = Keypair::new();
    let recipient_a = Keypair::new();
    let recipient_b = Keypair::new();
    let fee_receiver = Keypair::new();
    let decimals = 2;
    let airdrop_signature = client
        .request_airdrop(&fee_payer.pubkey(), 5_000_000_000)
        .await?;

    loop {
        let confirmed = client.confirm_transaction(&airdrop_signature).await?;
        if confirmed {
            break;
        }
    }

    let mint = Keypair::new();
    let mint_space =
        ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::TransferFeeConfig])?;

    let mint_rent = client
        .get_minimum_balance_for_rent_exemption(mint_space)
        .await?;

    let mint_blockhash = client.get_latest_blockhash().await?;
    let mint_transaction = Transaction::new_signed_with_payer(
        &[
            create_account(
                &fee_payer.pubkey(), // Account funding account creation.
                &mint.pubkey(), // New mint account to create.
                mint_rent, // Lamports funding the mint account rent.
                mint_space as u64, // Account size in bytes for the mint plus TransferFeeConfig.
                &TOKEN_2022_PROGRAM_ID, // Program that owns the mint account.
            ),
            // !mark(1:8)
            initialize_transfer_fee_config(
                &TOKEN_2022_PROGRAM_ID, // Token program that owns the mint.
                &mint.pubkey(), // Mint account that stores the TransferFeeConfig extension.
                Some(&fee_payer.pubkey()), // Authority allowed to update the transfer fee later.
                Some(&fee_payer.pubkey()), // Value stored in the mint's `withdraw_withheld_authority` field.
                150, // Transfer fee in basis points.
                10, // Maximum fee charged on each transfer.
            )?,
            initialize_mint(
                &TOKEN_2022_PROGRAM_ID, // Program that owns the mint account.
                &mint.pubkey(), // Mint account to initialize.
                &fee_payer.pubkey(), // Authority allowed to mint new tokens.
                Some(&fee_payer.pubkey()), // Authority allowed to freeze token accounts.
                decimals, // Number of decimals for the token.
            )?,
        ],
        Some(&fee_payer.pubkey()),
        &[&fee_payer, &mint],
        mint_blockhash,
    );

    client.send_and_confirm_transaction(&mint_transaction).await?;

    let source_token_address = get_associated_token_address_with_program_id(
        &fee_payer.pubkey(),
        &mint.pubkey(),
        &TOKEN_2022_PROGRAM_ID,
    );
    let destination_a_token_address = get_associated_token_address_with_program_id(
        &recipient_a.pubkey(),
        &mint.pubkey(),
        &TOKEN_2022_PROGRAM_ID,
    );
    let destination_b_token_address = get_associated_token_address_with_program_id(
        &recipient_b.pubkey(),
        &mint.pubkey(),
        &TOKEN_2022_PROGRAM_ID,
    );
    let fee_receiver_token_address = get_associated_token_address_with_program_id(
        &fee_receiver.pubkey(),
        &mint.pubkey(),
        &TOKEN_2022_PROGRAM_ID,
    );

    let setup_blockhash = client.get_latest_blockhash().await?;
    let setup_transaction = Transaction::new_signed_with_payer(
        &[
            create_associated_token_account(
                &fee_payer.pubkey(),
                &fee_payer.pubkey(),
                &mint.pubkey(),
                &TOKEN_2022_PROGRAM_ID,
            ),
            create_associated_token_account(
                &fee_payer.pubkey(),
                &recipient_a.pubkey(),
                &mint.pubkey(),
                &TOKEN_2022_PROGRAM_ID,
            ),
            create_associated_token_account(
                &fee_payer.pubkey(),
                &recipient_b.pubkey(),
                &mint.pubkey(),
                &TOKEN_2022_PROGRAM_ID,
            ),
            create_associated_token_account(
                &fee_payer.pubkey(),
                &fee_receiver.pubkey(),
                &mint.pubkey(),
                &TOKEN_2022_PROGRAM_ID,
            ),
            mint_to_checked(
                &TOKEN_2022_PROGRAM_ID,
                &mint.pubkey(),
                &source_token_address,
                &fee_payer.pubkey(),
                &[],
                1_000,
                decimals,
            )?,
        ],
        Some(&fee_payer.pubkey()),
        &[&fee_payer],
        setup_blockhash,
    );

    client.send_and_confirm_transaction(&setup_transaction).await?;

    let first_transfer_blockhash = client.get_latest_blockhash().await?;
    let first_transfer_transaction = Transaction::new_signed_with_payer(
        &[
            // !mark(1:11)
            transfer_checked_with_fee(
                &TOKEN_2022_PROGRAM_ID, // Token program that processes the transfer.
                &source_token_address, // Token account sending the transfer.
                &mint.pubkey(), // Mint with the transfer fee configuration.
                &destination_a_token_address, // Token account receiving the transfer.
                &fee_payer.pubkey(), // Signer approving the transfer.
                &[], // Additional multisig signers.
                200, // Token amount in base units.
                decimals, // Decimals defined on the mint.
                3, // Expected transfer fee for this transfer.
            )?,
        ],
        Some(&fee_payer.pubkey()),
        &[&fee_payer],
        first_transfer_blockhash,
    );
    client
        .send_and_confirm_transaction(&first_transfer_transaction)
        .await?;

    let withdraw_accounts_blockhash = client.get_latest_blockhash().await?;
    let withdraw_accounts_transaction = Transaction::new_signed_with_payer(
        &[
            // !mark(1:8)
            withdraw_withheld_tokens_from_accounts(
                &TOKEN_2022_PROGRAM_ID, // Token program that processes the withdraw.
                &mint.pubkey(), // Mint with the transfer fee configuration.
                &fee_receiver_token_address, // Token account receiving withdrawn fees.
                &fee_payer.pubkey(), // Signer matching the mint's `withdraw_withheld_authority`.
                &[], // Additional multisig signers.
                &[&destination_a_token_address], // Token accounts to withdraw withheld fees from.
            )?,
        ],
        Some(&fee_payer.pubkey()),
        &[&fee_payer],
        withdraw_accounts_blockhash,
    );
    client
        .send_and_confirm_transaction(&withdraw_accounts_transaction)
        .await?;

    let second_transfer_blockhash = client.get_latest_blockhash().await?;
    let second_transfer_transaction = Transaction::new_signed_with_payer(
        &[
            // !mark(1:11)
            transfer_checked_with_fee(
                &TOKEN_2022_PROGRAM_ID, // Token program that processes the transfer.
                &source_token_address, // Token account sending the transfer.
                &mint.pubkey(), // Mint with the transfer fee configuration.
                &destination_b_token_address, // Token account receiving the transfer.
                &fee_payer.pubkey(), // Signer approving the transfer.
                &[], // Additional multisig signers.
                200, // Token amount in base units.
                decimals, // Decimals defined on the mint.
                3, // Expected transfer fee for this transfer.
            )?,
        ],
        Some(&fee_payer.pubkey()),
        &[&fee_payer],
        second_transfer_blockhash,
    );
    client
        .send_and_confirm_transaction(&second_transfer_transaction)
        .await?;

    let harvest_blockhash = client.get_latest_blockhash().await?;
    let harvest_transaction = Transaction::new_signed_with_payer(
        &[
            // !mark(1:5)
            harvest_withheld_tokens_to_mint(
                &TOKEN_2022_PROGRAM_ID, // Token program that processes the harvest.
                &mint.pubkey(), // Mint that collects harvested withheld fees.
                &[&destination_b_token_address], // Token accounts to harvest withheld fees from.
            )?,
        ],
        Some(&fee_payer.pubkey()),
        &[&fee_payer],
        harvest_blockhash,
    );
    client.send_and_confirm_transaction(&harvest_transaction).await?;

    let finalize_blockhash = client.get_latest_blockhash().await?;
    let finalize_transaction = Transaction::new_signed_with_payer(
        &[
            // !mark(1:7)
            withdraw_withheld_tokens_from_mint(
                &TOKEN_2022_PROGRAM_ID, // Token program that processes the withdraw.
                &mint.pubkey(), // Mint storing harvested withheld fees.
                &fee_receiver_token_address, // Token account receiving withdrawn fees.
                &fee_payer.pubkey(), // Signer matching the mint's `withdraw_withheld_authority`.
                &[], // Additional multisig signers.
            )?,
            // !mark(1:8)
            set_transfer_fee(
                &TOKEN_2022_PROGRAM_ID, // Token program that owns the mint.
                &mint.pubkey(), // Mint whose next transfer fee configuration is updated.
                &fee_payer.pubkey(), // Authority allowed to update the transfer fee later.
                &[], // Additional multisig signers.
                250, // New transfer fee in basis points.
                25, // New maximum fee for the next transfer fee configuration.
            )?,
        ],
        Some(&fee_payer.pubkey()),
        &[&fee_payer],
        finalize_blockhash,
    );
    client.send_and_confirm_transaction(&finalize_transaction).await?;

    let destination_a_account = client.get_account(&destination_a_token_address).await?;
    let destination_a_state = StateWithExtensions::<Account>::unpack(&destination_a_account.data)?;
    let destination_b_account = client.get_account(&destination_b_token_address).await?;
    let destination_b_state = StateWithExtensions::<Account>::unpack(&destination_b_account.data)?;
    let fee_receiver_account = client.get_account(&fee_receiver_token_address).await?;
    let fee_receiver_state = StateWithExtensions::<Account>::unpack(&fee_receiver_account.data)?;
    let mint_account = client.get_account(&mint.pubkey()).await?;
    let mint_state = StateWithExtensions::<Mint>::unpack(&mint_account.data)?;

    println!("Mint: {}", mint.pubkey());
    println!("Destination A Balance: {}", destination_a_state.base.amount);
    println!(
        "Destination A Transfer Fee Amount: {:#?}",
        destination_a_state.get_extension::<TransferFeeAmount>()?
    );
    println!("Destination B Balance: {}", destination_b_state.base.amount);
    println!(
        "Destination B Transfer Fee Amount: {:#?}",
        destination_b_state.get_extension::<TransferFeeAmount>()?
    );
    println!("Fee Receiver Balance: {}", fee_receiver_state.base.amount);
    println!(
        "Fee Receiver Transfer Fee Amount: {:#?}",
        fee_receiver_state.get_extension::<TransferFeeAmount>()?
    );
    println!(
        "Transfer Fee Config: {:#?}",
        mint_state.get_extension::<TransferFeeConfig>()?
    );

    Ok(())
}
```

</CodeTabs>
