Using Fuel Tanks

Subsidize fees for your players while reducing overall costs.

A Fuel tank is a pool that holds Enjin Coins (ENJ) which is used to cover transaction fees for eligible users. Each Fuel Tank is designed to minimize transaction costs, resulting in lower expenses for platform operations.

Fuel Tanks are flexible and dynamic, allowing customization based on specific rules and requirements. They operate based on a set of rules, making it possible to target specific actions or accounts meeting specific criteria.

📘

What you'll need:

Fuel Tanks offer versatile rule sets for various use cases, allowing customization:

  • Whitelisted Callers: Select which wallets can receive subsidized transactions, ideal for rewarding users.
  • Whitelisted Collections: Choose collections with covered transaction fees to boost their activity.
  • Require Token: Users must hold a specific NFT for free transactions access.
  • Permitted Extrinsics: Subsidize specific transaction types, e.g., marketplace transactions.
  • Permitted Calls: Define transactions based on inputs and parameters, promoting certain trades.
  • User Fuel Budget: Set limits on individual fuel consumption for security.
  • Tank Fuel Budget: Define collective fuel usage to extend Fuel Tank lifespan.
  • Max Fuel Burn: Control fuel consumption per transaction for predictability.
  • Freezing: Pause Fuel Tank usage as a safety measure.

These rules enhance the Enjin Blockchain experience, sparking new products and business models.

This tutorial guides you through setting up a Fuel Tank with specific functionality, including creating rules and customizing it to fit your needs, enabling you to reduce transaction costs for your users.

There are two ways to create a Fuel Tank:

Option A. Using the Enjin Dashboard

🚧

PermittedExtrinsics is Only Available via GraphQL

Please note that while creating a Fuel Tank is possible through the Enjin Platform User Interface, the specific rule required for this tutorial, PermittedExtrinsics, is currently only available via the GraphQL API or SDKs.

Therefore, this tutorial will only cover instructions for setting up a Fuel Tank with PermittedExtrinsics rule using the GraphQL API or SDKs.

In the Platform menu, navigate to "Fuel Tanks". Then, click the "Create Fuel Tank" button.

Option B. Using the Enjin API & SDKs

📘

Make sure to use the Fuel Tank Endpoint

  • Testnet: http://platform.canary.enjin.io/graphql/fuel-tanks
  • Mainnet: http://platform.enjin.io/graphql/fuel-tanks

Try the Beam Playground here:

This mutation will set up a new transaction that once finalized on-chain will create the new fuel tank on-chain.

mutation CreateFuelTank{
  CreateFuelTank(
    name: "Collection Token Transfers" #Specify the Fuel Tank name
    providesDeposit: false #This is set to false since we don't need to provide token deposits for token transfer transactions
    dispatchRules: [{
      permittedExtrinsics: [BatchTransfer] #This rule specifies that only batch transfers are subsidized
      whitelistedCollections: [36105] #This rule ensures that only the specified collection is subsidized
    }]
  ){
    id
    method
    state
  }
}
curl -X POST "https://platform.enjin.io/graphql" \
-H "Content-Type: application/json" \
-H "Authorization: enjin_api_key" \
-d '{"query": "mutation CreateFuelTank { CreateFuelTank(name: \"Collection Token Transfers\", providesDeposit: false, dispatchRules: [{ permittedExtrinsics: [BatchTransfer], whitelistedCollections: [36105] }]) { id method state } }"}'
using System.Text.Json;
using Enjin.Platform.Sdk;
using Enjin.Platform.Sdk.FuelTanks;

// Create the array of dispatch rules for the fuel tank
var dispatchRules = new List<DispatchRuleInputType>()
{
    new DispatchRuleInputType()
        .SetPermittedExtrinsics(TransactionMethod.BatchTransfer) // This rule specifies that only batch transfers are subsidized
        .SetWhitelistedCollections(36105) // This rule ensures that only the specified collection is subsidized
};

// Setup the mutation
var createFuelTank = new CreateFuelTank()
    .SetName("Collection Token Transfers")
    .SetProvidesDeposit(false)
    .SetDispatchRules(dispatchRules.ToArray());

// Define and assign the return data fragment to the mutation
var transactionFragment = new TransactionFragment()
    .WithId()
    .WithMethod()
    .WithState();

createFuelTank.Fragment(transactionFragment);

// Create and auth a client to send the request to the platform
var client = PlatformClient.Builder()
    .SetBaseAddress("https://platform.canary.enjin.io")
    .Build();
client.Auth("Your_Platform_Token_Here");

// Send the request and write the output to the console.
// Only the fields that were requested in the fragment will be filled in,
// other fields which weren't requested in the fragment will be set to null.
var response = await client.SendCreateFuelTank(createFuelTank);
Console.WriteLine(JsonSerializer.Serialize(response.Result.Data));
fetch('https://platform.canary.enjin.io/graphql', {
  method: 'POST',
  headers: {'Content-Type': 'application/json','Authorization': 'Your_Platform_Token_Here'},
  body: JSON.stringify({
    query: `
      mutation CreateFuelTank
      (
        $name: String!
        $provide_deposit: Boolean!
      ) {
        CreateFuelTank(
          name: $name
          providesDeposit: $provide_deposit
          dispatchRules: [{
            permittedExtrinsics: [BatchTransfer] #This rule specifies that only batch transfers are subsidized
            whitelistedCollections: [36105] #This rule ensures that only the specified collection is subsidized
          }]
        ){
          id
          method
          state
        }
      }
    `,
    variables: {
      name: "Collection Token Transfers", //Specify the Fuel Tank name
      provide_deposit: false //This is set to false since we don't need to provide token deposits for token transfer transactions
    }
  }),
})
.then(response => response.json())
.then(data => console.log(data));
const axios = require('axios');

axios.post('https://platform.canary.enjin.io/graphql', {
  query: `
    mutation CreateFuelTank
    (
      $name: String!
      $provide_deposit: Boolean!
    ) {
      CreateFuelTank(
        name: $name
        providesDeposit: $provide_deposit
        dispatchRules: [{
          permittedExtrinsics: [BatchTransfer] #This rule specifies that only batch transfers are subsidized
          whitelistedCollections: [36105] #This rule ensures that only the specified collection is subsidized
        }]
      ){
        id
        method
        state
      }
    }
  `,
  variables: {
    name: "Collection Token Transfers", //Specify the Fuel Tank name
    provide_deposit: false //This is set to false since we don't need to provide token deposits for token transfer transactions
  }
}, {
  headers: {'Content-Type': 'application/json','Authorization': 'Your_Platform_Token_Here'}
})
.then(response => console.log(response.data))
.catch(error => console.error(error));
import requests

query = '''
mutation CreateFuelTank
(
  $name: String!
  $provide_deposit: Boolean!
) {
  CreateFuelTank(
    name: $name
    providesDeposit: $provide_deposit
    dispatchRules: [{
      permittedExtrinsics: [BatchTransfer] #This rule specifies that only batch transfers are subsidized
      whitelistedCollections: [36105] #This rule ensures that only the specified collection is subsidized
    }]
  ){
    id
    method
    state
  }
}
'''

variables = {
  'name': "Collection Token Transfers", #Specify the Fuel Tank name
  'provide_deposit': False #This is set to false since we don't need to provide token deposits for token transfer transactions
}

response = requests.post('https://platform.canary.enjin.io/graphql',
  json={'query': query, 'variables': variables},
  headers={'Content-Type': 'application/json', 'Authorization': 'Your_Platform_Token_Here'}
)
print(response.json())
// Coming Soon!

A WebSocket event will also be fired so you can pick up the Fuel Tank creation in real time by listening to the app channel on the WebSocket.

📘

More Fields and Arguments Available!

The examples here illustrate basic uses of the CreateFuelTank mutation. However, this mutation supports many more arguments and settings not shown in these examples.

For a comprehensive overview of all available settings and their descriptions for the CreateFuelTank mutation, please refer to our GraphQL Schema on Apollo.

This resource will help you to fully utilize the capabilities of the CreateFuelTank mutation and tailor it to your specific needs.

For instance, you'll find settings such as allowing the fuel tank to provide Storage Deposits with the providesDeposit flag, or setting various account rules and dispatch rules with the accountRules and dispatchRules objects.

Dispatching a Call Using a Fuel Tank

To request a transaction call to be subsidized by a fuel tank, use the Dispatch/DispatchAndTouch mutation.

📘

The Fuel Tank requires a UserAccount to dispatch?

Use the DispatchAndTouch mutation to create a UserAccount and Dispatch at the same time in a single transaction.

Step #1: Prepare The Mutation

First, prepare the mutation you wish to dispatch. In this example, we'll dispatch a call to send a MultiTokenfrom one account to another:

mutation TransferNFT{
  SimpleTransferToken(
    collectionId: 3298
    recipient: "efQh8FzLm6oH3dmTU3HWqGrtm6Xcuu1WG33N2Ka9fzo5MFFAr"
    params: {tokenId: {integer: 1} amount: 1}
  ){
    id
    encodedData
  }
}
curl -X POST "https://platform.enjin.io/graphql" \
-H "Content-Type: application/json" \
-H "Authorization: enjin_api_key" \
-d '{"query": "mutation TransferNFT { SimpleTransferToken(collectionId: 3298, recipient: \"efQh8FzLm6oH3dmTU3HWqGrtm6Xcuu1WG33N2Ka9fzo5MFFAr\", params: { tokenId: { integer: 1 }, amount: 1 }) { id encodedData } }"}'

Step #2: Prepare The Dispatch Mutation

Next, you need to convert the mutation call into a String. Remove all new lines and escape double quotation marks:

mutation TransferNFT{SimpleTransferToken(collectionId: 3298 recipient: \"efQh8FzLm6oH3dmTU3HWqGrtm6Xcuu1WG33N2Ka9fzo5MFFAr\" params: {tokenId: {integer: 1} amount: 1}){id encodedData}}

To escape quotation marks you can use online tools such as https://tools.knowledgewalls.com/online-escape-single-or-double-quotes-from-string.

Step #3: Send the Disaptch Call

Insert the mutation String from Step #2 into a Dispatch mutation call "query" parameter and send it:

mutation Dispatch {
  Dispatch(
    tankId: "efQqqMFeDXMSQ43rShznQQ5Aq5pnMUKBfvTQHntatMmF4JZou" #Specify the Fuel Tank ID to dispatch with
    ruleSetId: 0  #Specify the ruleset to dispatch with
    dispatch: {
      call:MULTI_TOKENS  #Specify the pallet to use for the transaction
      query:"mutation TransferNFT{SimpleTransferToken(collectionId: 3298 recipient: \"efQh8FzLm6oH3dmTU3HWqGrtm6Xcuu1WG33N2Ka9fzo5MFFAr\" params: {tokenId: {integer: 1} amount: 1}){id encodedData}}" #Insert the mutation to dispatch.
    }
  ){
    id
    method
    state
  }
}
curl -X POST "https://platform.enjin.io/graphql" \
-H "Content-Type: application/json" \
-H "Authorization: enjin_api_key" \
-d '{"query": "mutation Dispatch { Dispatch(tankId: \"efQqqMFeDXMSQ43rShznQQ5Aq5pnMUKBfvTQHntatMmF4JZou\", ruleSetId: 0, dispatch: { call: MULTI_TOKENS, query: \"mutation TransferNFT{SimpleTransferToken(collectionId: 3298 recipient: \\\"efQh8FzLm6oH3dmTU3HWqGrtm6Xcuu1WG33N2Ka9fzo5MFFAr\\\" params: {tokenId: {integer: 1} amount: 1}){id encodedData}}\" }) { id method state } }"}'