# Having Users Pay RAM

A very common question I see is something along the following lines.

"I want to have users send NFTs to my contract, and store the asset IDs in a table row, but I don't want to pay the RAM. If I try to charge the user, I get an error!"

This is because you can not increase the RAM usage of another user unless they directly sign the action where the RAM is being increased. In other words, if a user signs an action on your contract, you **can** charge them RAM.

However, if you receive a transfer from a user, then they signed the `transfer` action on another contract. **Not your contract**. So you can not increase their RAM during that transfer.

There are way's around this. Let me show you a little trick that I use. Let's say that I want to do exactly what I said above - accept NFT deposits and store the asset IDs in a table.

That table might look something like this.

```cpp
struct [[eosio::table, eosio::contract(CONTRACT_NAME)]] deposits {
  eosio::name user;
  vector<uint64_t> deposited_nfts;

  uint64_t primary_key() const { return user.value; }
};
using deposits_table = eosio::multi_index< "deposits"_n, deposits >;
```

If I try to add an asset ID into the `deposited_nfts` vector, then I will get an error along the lines of `can not increase the RAM usage of another wallet`. So, what I can do is add another field in the table struct, like this.

```cpp
struct [[eosio::table, eosio::contract(CONTRACT_NAME)]] deposits {
  eosio::name user;
  vector<uint64_t> deposited_nfts;
  vector<uint64_t> announced_nfts;

  uint64_t primary_key() const { return user.value; }
};
using deposits_table = eosio::multi_index< "deposits"_n, deposits >;
```

Now I have 2 vectors. What I can do is add an action to my contract like this.

```cpp
ACTION mycontract::announcenfts(const name& user, const vector<uint64_t>& asset_ids){
    require_auth( user );
    deposits_table deposits_t = deposits_table( _self, _self.value );
    auto itr = deposits_t.find( user.value );
    
    if( itr == deposits_t.end() ){
        deposits_t.emplace(user, [&](auto &row){
            row.user = user;
            row.announced_nfts = asset_ids;
        });
    } else {
        // modify the row, you get the point
    }
}
```

Now I have charged the user RAM for the asset IDs they are going to deposit. Then, my notification handler might look like this.

```cpp
void receive_nft_transfer(name owner, name receiver, vector<uint64_t>& ids, std::string memo){
    // run your safety checks to validate the transfer, then proceed
    
    deposits_table deposits_t = deposits_table( _self, _self.value );
    auto itr = deposits_t.require_find( from.value, "user not found" );
    vector<uint64_t> existing_nfts = itr->deposited_nfts;

    for( uint64_t& nft : asset_ids ){
        check( std::find( itr->announced_nfts.begin(), itr->announced_nfts.end(), nft ) != itr->announced_nfts.end(),
            "you did not announce one of the transferred NFTs" );
        existing_nfts.push_back( nft );
    }
    
    deposits_t.modify( itr, same_payer, [&](auto &row){
        row.deposited_nfts = existing_nfts;
        row.announced_nfts = {};
    });
}
```

Now, I am not increasing the users RAM. That RAM was already being used to store the asset IDs that were in the `announced_nfts` vector. All I did was remove them from there, and move them into the `deposited_nfts` vector.

This circumvents any errors related to charging RAM to an unauthorized account, and avoids your contract needing to pay any of the RAM costs.


---

# 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://waxdao.gitbook.io/wax-smart-contract-development-guide/tips-and-tricks/having-users-pay-ram.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.
