# Custom Transfers

### Overview

The ART20 module implements a sophisticated transfer mechanism that goes beyond simple ownership changes. It manages user balances, collection integrity, deny lists, and batch operations while ensuring proper state updates across the protocol.

### Transfer Functions

#### 1. Standard Transfer

```move
public entry fun transfer_art20(
    tokens: vector<NFT>,
    recipients: vector<address>,
    collection_cap: &CollectionCap,
    mut sender_balances: vector<UserBalance>,
    ctx: &mut TxContext
)
```

### Purpose

Enables secure transfer of NFTs while maintaining protocol state, balances, and collection integrity.

### Parameters

* `tokens`: Vector of NFTs to transfer
* `recipients`: Vector of recipient addresses
* `collection_cap`: Collection capability for validation
* `sender_balances`: Vector of sender's balance objects
* `ctx`: Transaction context

### Process Flow

1. **Initial Validation**

   ```move
   let sender = tx_context::sender(ctx);
   let token_count = vector::length(&tokens);
   let recipient_count = vector::length(&recipients);
   assert!(token_count == recipient_count, E_INVALID_LENGTH);
   ```
2. **Balance Verification**

   ```move
   let mut total_available = 0u64;
   let mut i = 0;
   while (i < vector::length(&sender_balances)) {
       let balance = vector::borrow(&sender_balances, i);
       total_available = safe_add(total_available, balance.balance);
       i = i + 1;
   };
   assert!(total_available >= token_count, E_INSUFFICIENT_BALANCE);
   ```
3. **Deny List Check**

   ```move
   check_deny_list_restrictions(collection_cap, sender);
   for (recipient in recipients) {
       check_deny_list_restrictions(collection_cap, recipient);
   }
   ```
4. **Transfer Execution**

   ```move
   let mut i = 0;
   while (i < token_count) {
       let recipient = *vector::borrow(&recipients, i);
       let token = vector::pop_back(&mut tokens);
       
       // Update balances
       update_balances(&mut sender_balances, token_count);
       
       // Create recipient balance if needed
       let recipient_balance = create_user_balance(
           collection_id,
           1,
           ctx
       );
       
       // Transfer token and balance
       transfer::public_transfer(token, recipient);
       transfer::transfer(recipient_balance, recipient);
       
       i = i + 1;
   };
   ```
5. **Event Emission**

   ```move
   event::emit(BatchTransferEvent {
       from: sender,
       recipients,
       token_ids,
       amounts,
       collection_id,
       timestamp: tx_context::epoch(ctx)
   });
   ```

#### 2. Batch Transfer

```move
public entry fun batch_transfer_art20(
    tokens: vector<NFT>,
    recipient: address,
    quantity: u64,
    collection_cap: &CollectionCap,
    sender_balances: vector<UserBalance>,
    ctx: &mut TxContext
)
```

### Special Features

1. **Balance Management**
   * Tracks user token balances
   * Automatically creates recipient balances
   * Handles balance updates atomically
2. **Security Checks**

   ```move
   // Collection verification
   assert!(token.collection_id == collection_cap_id, E_COLLECTION_MISMATCH);

   // Balance verification
   assert!(current_balance >= quantity, E_INSUFFICIENT_BALANCE);

   // Deny list check
   assert!(!is_denied(collection_cap, recipient), E_ADDRESS_DENIED);
   ```
3. **Batch Processing**
   * Efficient handling of multiple transfers
   * Atomic updates across all operations
   * Event emission for batch transfers

### Integration Guide

#### 1. Basic Transfer

```move
// Transfer single NFT
public fun transfer_single(
    nft: NFT,
    recipient: address,
    collection_cap: &CollectionCap,
    user_balance: &mut UserBalance,
    ctx: &mut TxContext
) {
    let tokens = vector::singleton(nft);
    let recipients = vector::singleton(recipient);
    let balances = vector::singleton(user_balance);
    
    transfer_art20(tokens, recipients, collection_cap, balances, ctx);
}
```

#### 2. Batch Transfer Example

```move
// Transfer multiple NFTs to single recipient
public fun transfer_batch(
    nfts: vector<NFT>,
    recipient: address,
    quantity: u64,
    collection_cap: &CollectionCap,
    user_balance: &mut UserBalance,
    ctx: &mut TxContext
) {
    let balances = vector::singleton(user_balance);
    
    batch_transfer_art20(nfts, recipient, quantity, collection_cap, balances, ctx);
}
```

### Error Handling

Common errors and their meanings:

```
```

| Error Code               | Description                      | Solution                           |
| ------------------------ | -------------------------------- | ---------------------------------- |
| E\_INSUFFICIENT\_BALANCE | Sender lacks required balance    | Verify balance before transfer     |
| E\_COLLECTION\_MISMATCH  | NFT doesn't belong to collection | Check collection ID                |
| E\_ADDRESS\_DENIED       | Address in deny list             | Verify recipient status            |
| E\_INVALID\_LENGTH       | Mismatched vectors               | Ensure equal tokens and recipients |

### Events

1. **TransferEvent**
   * Emitted for individual transfers
   * Tracks from/to addresses, token ID, amount
2. **BatchTransferEvent**
   * Emitted for batch transfers
   * Includes all recipients and token IDs
   * Records timestamp and collection ID

### Best Practices

1. **Balance Management**
   * Always verify balances before transfer
   * Handle balance updates atomically
   * Clean up empty balances
2. **Security**
   * Implement deny list checks
   * Verify collection capability
   * Validate all addresses
3. **Gas Optimization**
   * Use batch transfers when possible
   * Clean up unused resources
   * Minimize storage operations

### Common Integration Patterns

1. **Marketplace Integration**

```move
public fun list_for_sale(
    nft: NFT,
    price: u64,
    collection_cap: &CollectionCap,
    user_balance: &mut UserBalance,
    ctx: &mut TxContext
) {
    // Verify ownership and balance
    // Transfer to marketplace contract
    transfer_art20(
        vector::singleton(nft),
        vector::singleton(get_marketplace_address()),
        collection_cap,
        vector::singleton(user_balance),
        ctx
    );
}
```

2. **Game Integration**

```move
public fun transfer_to_game(
    game_nfts: vector<NFT>,
    player: address,
    collection_cap: &CollectionCap,
    user_balance: &mut UserBalance,
    ctx: &mut TxContext
) {
    // Update game state
    // Transfer NFTs to player
    batch_transfer_art20(
        game_nfts,
        player,
        vector::length(&game_nfts),
        collection_cap,
        vector::singleton(user_balance),
        ctx
    );
}
```


---

# 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.artinals.com/artinals-protocol/art20/functions-and-entry-points/custom-transfers.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.
