# External Transaction Fee

Source: https://docs.settlemint.com/docs/architecture/components/token-features/external-transaction-fee
Fixed fee in a separate ERC-20 token, such as USDC, charged on every mint, burn, or transfer. Fee amounts use the fee token's units and allowance.



External Transaction Fee charges a fixed fee in a separate ERC-20 token, such as USDC, on every mint, burn, or transfer. The transferred token amount is not reduced; the payer must also hold and approve enough of the separate fee token.

## Interface [#interface]

Fees are denominated in the configured fee token and collected from the payer's allowance.

| Capability                        | Who can call      | Inputs                                                               | On-chain effect                             | Emits                  | Notes                                |
| --------------------------------- | ----------------- | -------------------------------------------------------------------- | ------------------------------------------- | ---------------------- | ------------------------------------ |
| Collect external fee on operation | Automatic (hook)  | Triggered on mint, burn, transfer                                    | Transfers fee token from payer to recipient | `ExternalFeeCollected` | Payer must have approved fee token   |
| Set fee amounts                   | `GOVERNANCE_ROLE` | Fixed mint, burn, and transfer fees in the fee token's smallest unit | Updates fee amounts                         | `FeesUpdated`          | Blocked after freeze                 |
| Set fee token                     | `GOVERNANCE_ROLE` | ERC-20 token address                                                 | Changes fee denomination token              | `FeeTokenUpdated`      | All payers must re-approve new token |
| Set fee recipient                 | `GOVERNANCE_ROLE` | Recipient address                                                    | Redirects future collections                | `FeeRecipientUpdated`  | Effective immediately                |
| Freeze fees                       | `GOVERNANCE_ROLE` | None                                                                 | Permanently locks configuration             | `FeesFrozen`           | Irreversible                         |

***

## Business impact [#business-impact]

* **Holders / payers:** Gross-based: payer must hold both the token being transferred and sufficient balance of the fee ERC-20 token with sufficient allowance to the fee contract. Every operation has an additional cost denominated in the external token.
* **Issuer / recipient:** Fee collected in a stable or known ERC-20 asset, enabling predictable fee revenue independent of the token's own price.
* **Economics:** Decouples fee economics from the token's own value. Useful when fees must be denominated in a stable asset.

***

## Amount units [#amount-units]

Configure mint, burn, and transfer fees in the external fee token, not in the asset's own token. For API calls, submit the raw smallest-unit amount for the configured fee token. In the dapp, the fee-setting form reads the fee token and scales the entered value with that token's decimals before submission.

If you change the fee token, review the amounts before operating the asset again. The same displayed amount can map to a different raw value when the new fee token uses different decimals.

***

## Risks & abuse cases [#risks--abuse-cases]

* **Transaction revert on insufficient allowance:** If the payer's external ERC-20 allowance is insufficient, the **entire transaction reverts**. Holders who have not approved the fee token will not be able to transfer.
* **Fee token price risk:** If the external fee token, such as a non-stable ERC-20, appreciates significantly, fee burden on payers may become prohibitive.
* **Fee lock-in after freeze:** Calling `freezeFees()` locks fee amounts permanently. Ensure fee levels are correct before freezing.

***

## Controls & guardrails [#controls--guardrails]

| Role              | Actions                                            | Recommended guardrail                                                 |
| ----------------- | -------------------------------------------------- | --------------------------------------------------------------------- |
| `GOVERNANCE_ROLE` | `setFees()`: set fee amounts per operation         | Call `freezeFees()` after launch to lock                              |
| `GOVERNANCE_ROLE` | `setFeeToken()`: set the external ERC-20 fee token | Audit carefully because changing fee token changes holder obligations |
| `GOVERNANCE_ROLE` | `setFeeRecipient()`: set collection destination    | Multi-sig controlled                                                  |
| `GOVERNANCE_ROLE` | `freezeFees()`: lock fee configuration permanently | **Call at launch**                                                    |

***

## Failure modes & edge cases [#failure-modes--edge-cases]

* **No allowance:** Payer with zero allowance on the fee token will see every transfer revert. Onboarding flows must prompt users to approve the fee token.
* **Fee token contract failure:** If the external ERC-20 contract is paused or fails, all token operations that trigger the fee hook will revert. Choose a battle-tested, non-upgradeable fee token.
* **Fee token address change:** Changing `feeToken` mid-deployment requires all payers to re-approve the new token. Coordinate with holder communication.

***

## Auditability & operational signals [#auditability--operational-signals]

* `ExternalFeeCollected(payer, feeToken, feeAmount, recipient)`: emitted per operation. Use for fee revenue tracking.
* `FeesUpdated(sender, feeToken, amounts, recipient)`: emitted on configuration changes.
* `FeesFrozen(sender)`: emitted once on freeze.

Fee totals shown for the active fee token are cumulative for that fee token. If governance changes the fee token and later switches back, the displayed total for the restored token includes fees collected before the earlier change. A fee token that has not collected fees yet starts at zero.

***

## Dependencies [#dependencies]

* **External ERC-20 token contract**: must be deployed and accessible. Payers must hold this token and approve the fee contract.
* Payer must have granted allowance to the feature contract before any transfer.

***

## Compatibility & ordering notes [#compatibility--ordering-notes]

* `supportsRewriting = false`: does not modify the token transfer amount.
* Order after Transaction Fee in the feature array (Transaction Fee rewrites the amount; External Transaction Fee collects separately and independently).
* Compatible with compliance modules: runs after compliance checks on the token amount.
* Compatible with all other features.

***

## Change impact [#change-impact]

* **Enable after launch:** Immediately applies to all subsequent operations. Existing holders must approve the fee token before their next transfer.
* **Disable:** No retroactive effect. Payer approvals on the fee token contract remain but become unused.
* **Fee amount change (pre-freeze):** Effective immediately for all subsequent operations.
* **Fee token change:** All payers must re-approve the new token address.

***

## See also [#see-also]

* [Token Features Catalog](/docs/architecture/components/token-features): return to the full feature catalog
* [Transaction Fee](/docs/architecture/components/token-features/transaction-fee): in-token fee collection alternative
* [Asset Contracts](/docs/architecture/components/asset-contracts): deployment architecture and role model
