# MsgTransferTokens

Executes token transfers between addresses.

## Proto Definition

```protobuf
message MsgTransferTokens {
  string creator = 1; // Address initiating the transfer
  string collectionId = 2; // Collection containing tokens to transfer
  repeated Transfer transfers = 3; // Transfer operations (must pass approvals)
}

message MsgTransferTokensResponse {
  repeated ApprovalUsed approvalsUsed = 1;
  repeated CoinTransferProto coinTransfers = 2;
  repeated Balance balancesTransferred = 3;
  repeated string reviewItems = 4;
}

message Transfer {
  // The address of the sender of the transfer.
  string from = 1;
  // The addresses of the recipients of the transfer.
  repeated string toAddresses = 2;
  // The balances to be transferred.
  repeated Balance balances = 3;
  // If defined, we will use the predeterminedBalances from the specified approval to calculate the balances at execution time.
  // We will override the balances field with the precalculated balances. Only applicable for approvals with predeterminedBalances set.
  PrecalculateBalancesFromApprovalDetails precalculateBalancesFromApproval = 4;
  // The Merkle proofs / solutions for all Merkle challenges required for the transfer.
  repeated MerkleProof merkleProofs = 5;
  // The ETH signature proofs / solutions for all ETH signature challenges required for the transfer.
  repeated ETHSignatureProof ethSignatureProofs = 6;
  // The memo for the transfer.
  string memo = 7;
  // The prioritized approvals for the transfer. By default, we scan linearly through the approvals and use the first match.
  // This field can be used to prioritize specific approvals and scan through them first.
  repeated ApprovalIdentifierDetails prioritizedApprovals = 8;
  // Whether to only check prioritized approvals for the transfer.
  // If true, we will only check the prioritized approvals and fail if none of them match (i.e. do not check any non-prioritized approvals).
  // If false, we will check the prioritized approvals first and then scan through the rest of the approvals.
  bool onlyCheckPrioritizedCollectionApprovals = 9;
  // Whether to only check prioritized approvals for the transfer.
  // If true, we will only check the prioritized approvals and fail if none of them match (i.e. do not check any non-prioritized approvals).
  // If false, we will check the prioritized approvals first and then scan through the rest of the approvals.
  bool onlyCheckPrioritizedIncomingApprovals = 10;
  // Whether to only check prioritized approvals for the transfer.
  // If true, we will only check the prioritized approvals and fail if none of them match (i.e. do not check any non-prioritized approvals).
  // If false, we will check the prioritized approvals first and then scan through the rest of the approvals.
  bool onlyCheckPrioritizedOutgoingApprovals = 11;
}

message PrecalculateBalancesFromApprovalDetails {
  string approvalId = 1;
  string approvalLevel = 2;  // "collection", "incoming", or "outgoing"
  string approverAddress = 3;  // "" if collection-level
  string version = 4 [(gogoproto.customtype) = "Uint", (gogoproto.nullable) = false];
  PrecalculationOptions precalculationOptions = 5;
}

message PrecalculationOptions {
  string overrideTimestamp = 1 [(gogoproto.customtype) = "Uint", (gogoproto.nullable) = false];
  repeated UintRange tokenIdsOverride = 2;
}
```

## Response

The response includes structured data about the transfer execution:

* **`approvalsUsed`**: Details of which approvals were matched and consumed for the transfer
* **`coinTransfers`**: Any coin transfers that occurred as side effects (e.g., from approval criteria with coin transfer requirements)
* **`balancesTransferred`**: The actual token balances that were transferred
* **`reviewItems`**: Advisory strings about the transaction (see [Review Items](https://github.com/trevormil/bitbadges-docs/blob/master/x-tokenization/concepts/approval-change-events.md#review-items))

## Auto-Scan vs Prioritized Approvals

The transfer approval system operates in two modes to balance efficiency and precision:

### Auto-Scan Mode (Default)

By default, the system automatically scans through available approvals to find a match for the transfer. This mode:

* **Works with**: Approvals using [Empty Approval Criteria](/token-standard/examples/empty-approval-criteria.md) (no side effects)
* **Behavior**: Automatically finds and uses the first matching approval
* **Use case**: Simple transfers without custom logic or side effects
* **No versioning required**: The system handles approval selection automatically

### Prioritized Approvals (Required for Side Effects)

**CRITICAL REQUIREMENT**: Any transfer with side effects or custom approval criteria MUST always be prioritized with proper versioning set. No exceptions.

#### Race Condition Protection

The versioning control ensures that before submitting, the user knows the exact approval they are using:

```typescript
"prioritizedApprovals": [
    {
        "approvalId": "abc123",
        "approvalLevel": "collection",
        "approverAddress": "",
        "version": "2" // Must specify exact version
    }
]
```

#### Example: Coin Transfer Approval

```typescript
// MUST be prioritized - has coin transfer side effects
"prioritizedApprovals": [
    {
        "approvalId": "reward-approval",
        "approvalLevel": "collection",
        "approverAddress": "",
        "version": "1"
    }
],
"onlyCheckPrioritizedCollectionApprovals": true
```

#### Example: Auto-Scan Safe Transfer

```typescript
// Can use auto-scan - no side effects
"prioritizedApprovals": [], // Empty - will auto-scan

// Only will succeed if it finds an approval has empty approval criteria with no custom logic
```

### Control Flags

* `onlyCheckPrioritizedCollectionApprovals`: If true, only check prioritized approvals
* `onlyCheckPrioritizedIncomingApprovals`: If true, only check prioritized incoming approvals
* `onlyCheckPrioritizedOutgoingApprovals`: If true, only check prioritized outgoing approvals

**Setting these to `true` is recommended when using prioritized approvals to ensure deterministic behavior.**

### Related Documentation

* [Empty Approval Criteria](/token-standard/examples/empty-approval-criteria.md) - Template for auto-scan compatible approvals
* [Approval Criteria](/token-standard/learn/approval-criteria.md) - Understanding approval complexity
* [Coin Transfers](/token-standard/learn/approval-criteria/usdbadge-transfers.md) - Side effect examples

## Transfer Validation Process

Each transfer undergoes a systematic validation process to ensure security and proper authorization:

### Validation Steps

```
PRE. CALCULATE BALANCES (if needed)
  └── If precalculateBalancesFromApproval is specified, we will use the predeterminedBalances from the specified approval to pre-calculate the balances at execution time.

1. BALANCE CHECK
   └── Verify sender has sufficient balances for the transfer including ownership times
   └── FAIL if insufficient balances

2. COLLECTION APPROVAL CHECK
   └── Scan collection-level approvals (prioritized first, then auto-scan) to find a match for the entire transfer
   └── If match found:
       ├── Check approval criteria (merkle proofs, amounts, timing, etc.) and constraints
       ├── Check if it overrides sender approvals (overridesFromOutgoingApprovals)
       ├── Check if it overrides recipient approvals (overridesToIncomingApprovals)
       └── PROCEED with override flags set
   └── Else:
        └── Continue scanning
   └── If some attempted transfer balances have no valid collection approval: FAIL

3. SENDER APPROVAL CHECK (if not overridden)
   └── Check sender's outgoing approvals for this transfer
   └── Verify approval criteria and constraints
   └── FAIL if no valid outgoing approval found

4. RECIPIENT APPROVAL CHECK (if not overridden)
   └── Check each recipient's incoming approvals
   └── Verify approval criteria and constraints
   └── FAIL if any recipient lacks valid incoming approval

5. EXECUTE TRANSFER
   └── Update balances
   └── Execute any approved side effects
   └── Emit transfer events
   └── SUCCESS
```

### Override Behavior

Collection approvals can override user-level approvals:

* **`overridesFromOutgoingApprovals: true`** - Forcefully skips sender approval check
* **`overridesToIncomingApprovals: true`** - Forcefully skips recipient approval checks

This allows collection managers to enable transfers that would otherwise be blocked by user settings.

### Failure Points

Transfers fail at the first validation step that doesn't pass:

1. **Insufficient Balances** - Sender doesn't own the tokens
2. **No Collection Approval** - No valid collection-level approval found
3. **Blocked by Sender** - Sender's outgoing approvals reject the transfer
4. **Blocked by Recipient** - Recipient's incoming approvals reject the transfer

### ETH Signature Proofs

ETH Signature Proofs are required when transfers use [ETH Signature Challenges](/token-standard/learn/approval-criteria/eth-signature-challenges.md). Each proof contains:

* **`nonce`**: The unique identifier that was signed
* **`signature`**: The Ethereum signature of the message `nonce + "-" + creatorAddress`

**Important**: Each signature can only be used once per challenge tracker. The system tracks used signatures to prevent replay attacks.

### Related Documentation

* [Transferability](/token-standard/learn/transferability.md) - Approval system overview
* [Collection Approvals](/token-standard/examples/building-collection-approvals.md) - Collection-level controls
* [User Approvals](/token-standard/examples/building-user-approvals.md) - User-level settings
* [ETH Signature Challenges](/token-standard/learn/approval-criteria/eth-signature-challenges.md) - Ethereum signature requirements

## Precalculating Balances

When using `precalculateBalancesFromApproval`, you can override certain calculation parameters using `precalculationOptions`. These options only apply when the corresponding flags are enabled in the approval's `IncrementedBalances`.

### PrecalculationOptions

| Field               | Type          | Description                                                      |
| ------------------- | ------------- | ---------------------------------------------------------------- |
| `overrideTimestamp` | string (Uint) | Override timestamp for ownership time calculation (milliseconds) |
| `tokenIdsOverride`  | UintRange\[]  | Override token IDs (must be single ID if provided)               |

**overrideTimestamp**:

* Only applies when `IncrementedBalances.durationFromTimestamp` is set and `allowOverrideTimestamp` is `true`
* If zero or not provided, uses current block time
* Used to calculate ownership times as `[overrideTimestamp, overrideTimestamp + durationFromTimestamp - 1]`

**tokenIdsOverride**:

* Only applies when `IncrementedBalances.allowOverrideWithAnyValidToken` is `true`
* Must contain exactly one `UintRange` with `start == end` (single token ID)
* Token ID must be in the collection's `validTokenIds`

For detailed documentation, see [Predetermined Balances](/token-standard/learn/approval-criteria/predetermined-balances.md#precalculation-options).

## Collection ID Auto-Lookup

If you specify `collectionId` as `"0"`, it will automatically lookup the latest collection ID created. This can be used if you are creating a collection and do not know the official collection ID yet but want to perform a multi-message transaction.

## Usage Example

```bash
# CLI command
bitbadgeschaind tx tokenization transfer-tokens '[tx-json]' --from sender-key
```

### JSON Example

```json
{
    "creator": "bb1initiator123...",
    "collectionId": "1",
    "transfers": [
        {
            "from": "bb1sender123...",
            "toAddresses": ["bb1recipient123..."],
            // Balances to transfer (can be left blank if you are using precalculateBalancesFromApproval)
            "balances": [
                {
                    "amount": "10",
                    "ownershipTimes": [
                        { "start": "1", "end": "18446744073709551615" }
                    ],
                    "tokenIds": [{ "start": "1", "end": "5" }]
                }
            ],
            // Specific approval to calculate balances dynamically for (from the approvalCriteria.predeterminedBalances)
            "precalculateBalancesFromApproval": {
                "approvalId": "approval-1",
                "approvalLevel": "collection",
                "approverAddress": "",
                "version": "1",
                "precalculationOptions": {
                    "overrideTimestamp": "0", // Optional: override timestamp (milliseconds)
                    "tokenIdsOverride": [] // Optional: override token IDs (must be single ID if provided)
                }
            },
            // Supply all merkle proofs for any merkle challenges that need to be satisfied
            "merkleProofs": [],
            // Supply all ETH signature proofs for any ETH signature challenges that need to be satisfied
            "ethSignatureProofs": [],
            // Memo for the transfer (can be left blank)
            "memo": "",

            // Any approval IDs that you want to prioritize for this transfer
            // Note: All approvals with side effects must be prioritized with proper versioning
            "prioritizedApprovals": [
                {
                    "approvalId": "abc123",
                    "approvalLevel": "collection",
                    "approverAddress": "", // blank for collection, otherwise the address of the approver
                    "version": "0"
                }
            ],

            // If specified, we will stop checking after the prioritized approvals list.
            // If false, we will check prioritized first, but then continue to check the rest of the approvals in auto-scan mode
            "onlyCheckPrioritizedCollectionApprovals": false,
            "onlyCheckPrioritizedIncomingApprovals": false,
            "onlyCheckPrioritizedOutgoingApprovals": false
        }
    ]
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.bitbadges.io/token-standard/messages/msg-transfer-tokens.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
