# Compliance Transfer

Source: https://docs.settlemint.com/docs/architects/flows/compliance-transfer
Step-by-step sequence for how DALP validates token transfers through
recipient identity checks, token-specific compliance modules, global
compliance policy, and post-transfer state hooks.




## System context [#system-context]

DALP checks transfer restrictions at the time each movement executes. A holder-initiated transfer, an allowance-based `transferFrom`, and a standard batch transfer all end in the token's state-update path, where the token verifies the recipient identity and asks the configured compliance contract whether the movement is allowed before balances change.

Custodian forced transfers are a separate exception path for governed recovery, legal, or compliance cases. These custodian-only operations bypass holder approval, standard freeze restrictions, and the configured compliance `canTransfer` check. The recipient must still pass the token's identity check before balances change. Review this sequence before you configure compliance rules or audit transfer behavior for a deployed token.

<Mermaid
  chart="`
erDiagram
  TOKEN ||--|| IDENTITY_REGISTRY : verifies_recipient
  IDENTITY_REGISTRY ||--o{ ONCHAIN_ID : maps_wallet_to
  TOKEN ||--|| COMPLIANCE_ENGINE : calls_after_identity_check
  COMPLIANCE_ENGINE ||--o{ COMPLIANCE_MODULE : evaluates_token_policy
  COMPLIANCE_ENGINE ||--|| GLOBAL_POLICY : delegates_system_policy
  COMPLIANCE_MODULE }o--o{ ONCHAIN_ID : reads_claims_when_needed
  TOKEN ||--o{ TRANSFER_EVENT : emits_after_success
`"
/>

During token movement, DALP reads identity, compliance state, balances, feature hooks, and external-call paths. That transfer path is the surface to review for flash-loan and reentrancy risks.

## Related [#related]

* [Identity & Compliance](/docs/compliance-security/security/identity-compliance)
* [Compliance Modules](/docs/compliance-security/compliance)
* [Transfer approval](/docs/compliance-security/compliance/transfer-approval)
* [Signing Flow](/docs/architects/flows/signing-flow)
* [Advanced accounts concept](/docs/architecture/concepts/account-abstraction)
* [Paymasters and gas sponsorship](/docs/architects/components/infrastructure/advanced-accounts/paymasters-and-gas-sponsorship)
* [SMART Protocol integration (ERC-3643)](/docs/architects/components/asset-contracts/smart-protocol-integration)

***

## Transfer validation sequence [#transfer-validation-sequence]

Standard transfers, including holder-initiated transfers, allowance-based transfers, and batch helpers, pass through the token's recipient identity check and compliance engine before any balances change.

<Mermaid
  chart="`
sequenceDiagram
  participant User
  participant Token as Token Contract
  participant Compliance as Compliance Engine
  participant Registry as Identity Registry
  participant Identity as OnchainID Contracts
  participant Modules as Compliance Modules

  User->>Token: transfer(to, amount)
  Token->>Registry: isVerified(to)
  Registry-->>Token: recipient identity result

  alt Recipient identity fails
      Token-->>User: ❌ TransferNotCompliant revert
      Note over User,Token: No module evaluation and no balance update
  else Recipient identity passes
      Token->>Compliance: canTransfer(from, to, amount)

      loop Each active in-scope module
          Compliance->>Modules: canTransfer(token, from, to, amount)

          alt Module requires claims
              Modules->>Registry: resolve sender or recipient identity
              Registry-->>Modules: OnchainID address
              Modules->>Identity: read claim topic, issuer, expiry
              Identity-->>Modules: claim data
              Modules->>Modules: Validate configured rule
          end

          alt Module allows
              Modules-->>Compliance: returns normally
          else Module blocks
              Modules-->>Compliance: ❌ revert with reason
              Compliance-->>Token: ❌ revert
              Token-->>User: ❌ Transfer blocked
          end
      end

      Compliance->>Compliance: delegate global policy check
      Compliance-->>Token: ✅ returns true
      Token->>Token: _transfer(from, to, amount)
      Note over Token: Balances updated
      Token->>Compliance: transferred(from, to, amount)

      loop Each active state hook
          Compliance->>Modules: transferred(token, from, to, amount)
          Modules->>Modules: Update module state
      end

      Token-->>User: ✅ Transfer complete
  end

`"
/>

### Step-by-step flow [#step-by-step-flow]

1. A caller uses `transfer(to, amount)`, `transferFrom(from, to, amount)`, or a standard batch helper that submits individual token transfers.
2. Prior to any balance update, the token checks the recipient identity and calls the configured compliance contract for the current `from`, `to`, and `amount`.
3. The identity registry verifies the recipient. If the recipient is not registered or verified, the token movement reverts. Balances do not change and compliance modules do not run.
4. The compliance contract evaluates active, in-scope modules in stored binding order, then delegates to the deployment's global compliance policy:
   * Each module receives the token movement context. Current module instances read their own stored configuration; adapted legacy modules receive their adapter configuration.
   * Modules that require claims can query the sender's or recipient's on-chain identity.
   * Claim validation checks the required topics, trusted issuers, expiry dates, and configured claim data.
   * The first failing module reverts and blocks the movement.
5. Once all checks pass, the token updates balances.
6. After the balance update, the token notifies the compliance contract so active in-scope modules can update their state. Investor count modules update holder counts. Supply tracking modules update accumulation totals. Time lock modules record acquisition timestamps. Transfer approval modules consume single-use approvals.

***

![Compliance verification checks gate all token transfers](/docs/screenshots/identity/verification-topics.webp)

## Where custody approval fits [#where-custody-approval-fits]

Compliance transfer validation decides whether the token contract may update balances. Signer and custody policy approval is a separate layer that you configure independently.

Put a rule on-chain when the token must reject the movement itself: identity status, trusted issuer claims, country rules, blocklists, supply caps, investor counts, time locks, and transfer approval requirements all belong there. Keep any rule in the custody or operating model when it controls signing authority, quorum approval, provider policy, or institutional exception handling. When in doubt, ask whether the rule stops the movement or controls who may authorise a transaction.

In a normal state-changing flow, DALP prepares the transaction, runs the applicable identity and compliance checks, then routes signing through the configured wallet or custody provider before broadcast. If a transfer fails compliance validation, the token state does not change.

If token validation passes but the custody provider, smart-wallet approval, or signer policy does not approve the request, the transaction is not submitted through that signing path. To trace the full path from request to broadcast, see the [signing flow](/docs/architects/flows/signing-flow) and [custody providers](/docs/architects/integrations/custody-providers) pages.

### Policy responsibility matrix [#policy-responsibility-matrix]

Use this split when you decide where a rule belongs: DALP token compliance, custody policy, or an external operating control.

| Control question                                                 | DALP on-chain control                                                                                                                                                                                                                                                 | Custody or operating control                                                                                                  |
| ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| May this wallet receive a mint or transfer?                      | Current token paths check recipient identity verification before mint or transfer balances change. Older registry paths fall back to registration checks.                                                                                                             | The operator decides how wallets are onboarded, reviewed, and recovered before registration or verification.                  |
| May this transfer, mint, or transfer approval pass token policy? | The configured compliance engine evaluates active modules and the deployment's global policy for the current token movement.                                                                                                                                          | The policy owner decides which rules, claim issuers, thresholds, and exception paths are appropriate for the asset programme. |
| May this mint exceed the instrument's issuance limit?            | Cap controls reject minting when the resulting supply would exceed the configured maximum supply. Asset classes with capped token extensions enforce the cap before the mint completes.                                                                               | The issuer and programme owner decide the authorised issuance size, approval evidence, and any later cap-change governance.   |
| Does this asset require collateral evidence before minting?      | Collateral-enabled asset classes validate the configured collateral topic and collateral ratio before minting. The mint reverts when the required collateral state does not support the requested amount.                                                             | Reserve operations, auditors, custodians, and external evidence systems own the off-chain reserve records and attestations.   |
| Is the token paused?                                             | Pausable asset classes expose pause and unpause controls. While paused, token issuance and transfers stay disabled until an authorised emergency operator unpauses the token.                                                                                         | The institution decides when a pause is warranted, who may approve it, and how incident evidence is recorded.                 |
| Is this signer allowed to submit the transaction?                | DALP exposes roles, signed requests, and transaction preparation. Token compliance still runs when a mint or transfer transaction reaches the contract.                                                                                                               | The custody provider or smart-wallet policy decides whether the signer, quorum, spend limit, or approval workflow can sign.   |
| Is a governed exception such as forced transfer appropriate?     | Custodian-only exception paths can bypass holder approval, standard freeze restrictions, and the configured compliance `canTransfer` check. Current token paths still require recipient identity verification; older registry paths fall back to registration checks. | Legal, compliance, and operations teams decide when the exception is permitted and preserve the evidence for that decision.   |
| Does an off-chain eligibility change block future movements?     | DALP enforces the change only after the relevant identity, claim, registry, or compliance-module state has been updated on-chain.                                                                                                                                     | The external compliance system and integration process own the decision, update timing, and reconciliation evidence.          |

DALP gives each asset a repeatable enforcement surface, but it does not replace the institution's custody policy, legal authority, reserve controls, or external compliance system. If a rule must stop token movement automatically, represent it in identity or compliance state. If a rule decides who may authorise a transaction or when an exception is allowed, keep it in the custody and operating model and make the handoff auditable. When in doubt, ask whether the rule stops the movement or controls who signs the transaction.

## Transfer approval controls [#transfer-approval-controls]

When a token uses TransferApproval for transfer validation, a standard transfer needs an active approval for the sender identity, recipient identity, and amount unless the installed module configuration or scope excludes that movement. You grant or revoke approvals through the token transfer approval API. The API resolves the submitted wallets to on-chain identities, resolves the installed transfer approval module from the token's current compliance configuration, and queues the approval or revocation transaction for execution.

Transfer approval validation happens before balances change. If approval validation applies and the required approval is missing, expired, revoked, already consumed, or too small for the requested amount, the compliance module blocks the transfer. After a successful transfer, the post-transfer hook records the consumption according to the module's configured approval mode.

## Key invariants [#key-invariants]

* When you attempt a transfer, DALP checks the current token, identity registry, compliance contract state, and applicable transfer approval state.
* Identity and compliance checks complete before balances change, so failed checks revert before token state is updated.
* `approve` only grants an allowance. The later `transferFrom` still updates token state through the same transfer hooks and compliance check.
* Standard batch helpers submit per-recipient token transfers, so each item is checked as its own movement.
* The first failing module stops evaluation and blocks the movement.
* Post-transfer hooks must succeed or the whole transfer reverts.
* Modules evaluate in configuration order. Put broad eligibility checks before more expensive stateful checks where possible.

## Gas and failed-execution behavior [#gas-and-failed-execution-behavior]

A failed compliance transfer does not partially move tokens. Recipient identity checks and compliance `canTransfer` evaluation run before the balance update. If the identity check fails, a module reverts, global policy rejects the movement, a post-transfer hook fails, or the transaction runs out of gas, the EVM reverts the transaction and token balances stay unchanged.

DALP transfer checks are bounded by the modules configured for the token and the deployment's global compliance policy. A standard transfer asks the compliance engine to evaluate token-specific modules and global modules in order. List-based modules and batch helpers still consume gas according to the configured list size or batch size, so operators should keep those configurations within tested limits.

Gas handling is separate from token-state enforcement. A reverted public-chain transaction can still consume gas from the submitting wallet or sponsor. DALP therefore treats gas management as an execution concern and compliance failure as an asset-state concern.

| Scenario                                        | Token-state result                                                                 | Gas and operator result                                                                             |
| ----------------------------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| Recipient identity is missing                   | No balances change. The token reverts before module evaluation.                    | Broadcast attempts can still consume gas.                                                           |
| A compliance module blocks the movement         | No balances change. The compliance check stops the transfer.                       | The caller or sponsor may pay for the reverted execution. Review the module reason before retrying. |
| A post-transfer module hook fails               | The whole transfer reverts, including the balance update and module state changes. | Treat the operation as failed and fix the hook or configuration before retrying.                    |
| A batch item fails in a standard batch transfer | The batch transaction does not complete.                                           | Split or correct the failing item before submitting the batch again.                                |

For sponsored account abstraction flows, sponsorship changes who funds eligible execution. Sponsorship does not bypass identity checks, compliance checks, custody approval, or final contract execution.

Operationally, gas protection combines protocol design with deployment monitoring. Apply these practices:

* Keep the active module set focused on the policy the asset needs.
* Put broad, low-cost eligibility checks before more expensive stateful checks.
* Monitor transaction receipts and failed transaction states so you can detect underfunded wallets, misconfigured modules, or unusually expensive transfer attempts.
* Treat gas funding for operator and user wallets as an operational control, not as a token-ledger exception.

## Flash-loan and reentrancy controls [#flash-loan-and-reentrancy-controls]

DALP asset tokens do not expose a native flash-loan entry point. Standard asset movements use the ERC-20 transfer surface and run the same recipient identity and compliance checks before balances change. A borrowed balance only matters to DALP if a transaction reaches the token through a supported transfer path and passes the configured token controls for the current `from`, `to`, and `amount`.

DALP separates token-ledger controls from external DeFi, voting, or valuation logic. The token exposes current balances and, where the asset class supports it, historical balance checkpoints and timestamp-based voting checkpoints. DALP does not provide a default time-weighted average balance oracle, and reading a DALP balance does not make an external lending, collateral, or voting protocol safe.

For flash-loan-sensitive integrations, use a balance reference that your protocol cannot create and consume inside the same transaction. A DeFi protocol that accepts a DALP token as collateral should use its own oracle and time-weighting policy, assess eligibility independently, and not rely on a same-transaction balance, or should read a prior checkpoint. A governance flow should read from voting checkpoints, not the holder's current balance. When the external protocol reads only the current balance during the same transaction, the mitigation must live in that protocol, not in the DALP transfer hook.

| Scenario                                                       | DALP token control                                                                                      | Required integration mitigation                                                                                                              |
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| Borrowed DALP tokens are moved into a DeFi protocol            | The incoming transfer still needs recipient identity and compliance approval before balances change.    | The DeFi protocol should not value collateral from a same-transaction balance alone; use an oracle, prior checkpoint, delay, or TWAB policy. |
| Borrowed tokens are used to influence voting or holder weight  | Voting-enabled assets expose timestamp-based checkpoints for voting power.                              | Read voting power from the relevant checkpoint, not the caller's current balance after an intra-transaction transfer.                        |
| A protocol needs historic balances for eligibility or exposure | Asset classes with historical balances record checkpoints after mint, burn, and transfer state changes. | Choose and document the timepoint policy. DALP does not choose that policy for the external protocol.                                        |
| A custom wrapper adds lending, callbacks, or transfer hooks    | The wrapper is outside the standard DALP token transfer surface.                                        | Re-run the integration's security review and static analysis for the wrapper and any new callback paths.                                     |

Reentrancy-sensitive DALP token paths are bounded by the token surface:

| Area                           | Responsibility                                                                                                                                                                                                                       |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Standard transfers             | Recipient identity checks and compliance checks run before the balance update. Post-transfer compliance notifications run in the same transaction, so a failed hook reverts the whole transfer.                                      |
| Compliance module callbacks    | Modules are part of the trusted compliance configuration. A malicious module requires governance control to install; custom modules should be reviewed for callback behavior before activation.                                      |
| Feature payout flows           | `DALPAsset.payout()` and bond redemption entry points that make external transfers use reentrancy guards. Other configured payout or redemption features need deployment-specific review evidence for their own external-call paths. |
| ERC-777 and ERC-1363 callbacks | DALP asset tokens use an ERC-20 style transfer surface. ERC-777 send hooks and ERC-1363 transfer callbacks are not part of the standard DALP token interface.                                                                        |
| Custom transfer hooks          | Custom hooks are not part of the default transfer surface. If a deployment adds wrapper contracts or custom hook logic, those contracts must carry their own reentrancy protections and deployment-specific evidence.                |

Your security evidence for the deployed token scope should include static-analysis and review results for the actual token implementation, enabled feature contracts, compliance modules, and any wrapper contracts. For a clean reentrancy answer, that evidence should show no open untriaged reentrancy findings on the deployed token transfer and external-call paths. Use the analysis tools selected for the deployment, such as Slither or Mythril, or document the specific guard, role control, or accepted-risk decision for each finding.

## Bypass and exception controls [#bypass-and-exception-controls]

| Path                               | DALP behavior                                                                                                                                                                                                                                           |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transfer`                         | Runs the standard transfer validation flow before balances change.                                                                                                                                                                                      |
| `transferFrom`                     | Uses the caller's allowance, then runs the same transfer validation flow before balances change.                                                                                                                                                        |
| Standard batch transfer            | Executes each item through the standard transfer path. If one item reverts, the batch transaction does not complete.                                                                                                                                    |
| Custodian forced transfer          | Custodian authority may move tokens for governed recovery, legal, or compliance operations. Holder approvals, standard freeze restrictions, and the configured compliance `canTransfer` check do not apply. The recipient identity check still applies. |
| Delegatecall by external contracts | External wrapper contracts cannot change DALP token balances directly. If a wrapper calls the DALP token contract, the token's state-update path applies.                                                                                               |
| ERC-777 hooks                      | DALP asset tokens use an ERC-20 style token surface. ERC-777 send hooks are not part of the DALP transfer surface.                                                                                                                                      |
| Flash loan callbacks               | DALP asset tokens do not expose a flash-loan transfer path. If an external protocol returns DALP tokens through a normal token transfer, the normal token transfer checks still apply.                                                                  |

## Dynamic eligibility updates [#dynamic-eligibility-updates]

DALP checks eligibility against current on-chain platform state at the time the token movement is attempted. That includes the current identity registry, trusted issuer and claim state, and the configured compliance modules for the asset.

If eligibility changes in an off-chain compliance or investor system, DALP can only enforce that change after the relevant registry, claim, or compliance state has been updated on-chain. The lag between an external eligibility decision and on-chain enforcement is your operating and integration responsibility, not a fixed DALP protocol delay.

***

## Failure modes [#failure-modes]

| Failure                                   | Cause                                                                                                                   | Behavior                                                        |
| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| Recipient identity not registered         | Recipient wallet has no OnchainID mapping                                                                               | Immediate revert, no module evaluation                          |
| Recipient identity is not verified        | Recipient fails the registry's current identity policy                                                                  | Immediate revert, no module evaluation                          |
| Transfer approval is not usable           | Approval validation applies, and the approval is missing, expired, revoked, already used, or below the requested amount | The transfer approval module reverts before balances change     |
| Module claim rule fails                   | Required claim topic, issuer, expiry, or value fails                                                                    | The evaluating module reverts with its configured denial reason |
| Module limit exceeded                     | Supply cap, investor count, or holding period violated                                                                  | The evaluating module reverts with its configured denial reason |
| Global compliance policy rejects movement | Deployment-level compliance policy blocks the transfer                                                                  | The compliance check reverts before balances change             |
| State hook failure                        | Post-transfer module state update fails                                                                                 | Entire transfer reverts                                         |

***

## See also [#see-also]

* [Claims and identity](/docs/architecture/concepts/claims-and-identity) - how wallets, OnchainID, claim topics, and trusted issuers fit together
* [Identity & Compliance](/docs/compliance-security/security/identity-compliance) - OnchainID architecture and two-layer policy model
* [Compliance Modules](/docs/compliance-security/compliance) - full catalog of built-in modules
* [Signing Flow](/docs/architects/flows/signing-flow) - end-to-end transaction signing including custody layer
