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.
When dispatching a transaction via a Fuel Tank, the following checks must pass:
- The Fuel Tank is not frozen.
- The Fuel Tank is funded with enough Enjin Coins.
- The dispatcher account is allowed to use the Fuel Tank.
- The Fuel Tank allows dispatching this transaction.
What you'll need:
- Some Enjin Coin on Enjin / Canary Matrixchain to pay for Transaction Fees, and for funding the tank.
You can obtain cENJ (Canary ENJ) for testing from the Canary faucet.- An Enjin Platform Account.
Tank Rules
Fuel Tanks offer versatile rules for various use cases, allowing customization.
Dispatch Rules
Rule Set
When a call is made to a fuel tank (also known as "Dispatching"), it must be made in accordance with a set of rules. These rules, known as rule sets, can include multiple individual Dispatch Rules that determine the validity of the call. A fuel tank can have multiple rule sets, each of which controls access and permissions to the fuel tank's functionality and resources.
Types of Dispatch Rules:
Whitelisted Callers
: Subsidize Transactions dispatched from certain Wallet Accounts.Whitelisted Collections
: Subsidize Transactions involving specific Collection.Require Token
: Subsidize Transactions only if the user holds a specific NFT.WhitelistedPallets
: Subsidize Transactions involving specific Pallet.Permitted Extrinsics
: Subsidize Transactions involving specific Extrinsics, e.g. marketplace CreateListing transactions.Permitted Calls
: Subsidize Transactions involving specific Extrinsics and parameters.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 Per Transaction
: Control fuel consumption per transaction for predictability.Require Signature
: Subsidize Transactions which were signed by a specific Wallet Account.
These rules enhance the Enjin Blockchain experience, sparking new products and business models.
RequireAccount Parameter
In addition to Dispatch Rules, a Rule Set may require the dispatching account to have an existing Fuel Tank User Account in order to dispatch a call. This is configured by setting the Rule Set's requireAccount
parameter to true.
Account Rules
Adding an account to the Fuel Tank User Accounts can be done in two ways:
- In advance with the
add_account
extrinsic. - When dispatching a call with the
dispatch_and_touch
extrinsic.
In both ways, the account is added to the tank's User Accounts only if it's successfully validated by the tank's Account Rules.
Note: if the dispatcher is not the tank owner, he may add itself to the User Accounts only if UserAccountManagement is configured
Types of Account Rules:
Whitelisted Callers
: Only listed accounts are able to add their account to the Fuel Tank's User Accounts.Require Token
: Only accounts that hold the specified token are able to add their account to the Fuel Tank's User Accounts.
User Account Management
By default, only the Fuel Tank owner has permissions to add accounts to the Fuel Tank User Accounts.
However, the tank can be configured to allow accounts to add themselves to the Fuel Tank User Accounts. This is configured by providing the UserAccountManagement
argument.
Setting tankReservesAccountCreationDeposit
to True
will also make the tank subsidize the User Account Storage Deposit.
Coverage Policy
By default, the fuel tank will subsidize only Transaction Fees.
To cover both Transaction Fees and any Storage Deposit the dispatched call may require, set the Coverage Policy to FEES_AND_DEPOSIT
Creating Fuel Tanks
Now that we have a basic understanding of how Fuel Tanks are structured, let's go through setting up some Fuel Tanks with specific functionality, including creating rules and customizing it to fit your needs, enabling you to reduce transaction costs for your users.
User Interface
This guide will demonstrate how to create various fuel tanks with the GraphQL API.
Note that you may also use the User Interface to create Fuel Tanks.To create a Fuel Tank using the Platform's User Interface, navigate to "Fuel Tanks" in the Platform Menu. Then, click the "Create Fuel Tank" button.
Feature Availability Notice
Please be aware that the following arguments are currently unavailable on the Enjin Platform:
PermittedExtrinsics
cannot be set via the Enjin Platform UI.WhitelistedPallets
is not supported on the Enjin Platform, both on the UI and API.requireAccount
is also not supported on the Enjin Platform, both on the UI and API.We will update the documentation once these options are available.
Code snippets with these arguments are provided for illustrative purposes only. If you wish to create a fuel tank with these options now, please use the Enjin Console at console.enjin.io.
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:
Subsidize Token Transfers For A Collection
The following mutation will set up a fuel tank that only subsidizes transactions that contain a BatchTransfer
extrinsic, and only if it involves a token from the collection with ID 36,105.
mutation CreateFuelTank{
CreateFuelTank(
name: "Collection Token Transfers" #Specify the Fuel Tank name
coveragePolicy: FEES #This is set to FEES since we only want to subsidize transaction fees, and we don't need to provide storage deposits for token transfer transactions
reservesAccountCreationDeposit: null #This is set to null since we don't want to allow tank account creations
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 --location 'https://platform.canary.enjin.io/graphql' \
-H 'Content-Type: application/json' \
-H 'Authorization: enjin_api_key' \
-d '{"query":"mutation CreateFuelTank(\r\n $name: String!\r\n $coveragePolicy: CoveragePolicy\r\n $permittedExtrinsics: [TransactionMethod!]\r\n $whitelistedCollections: [BigInt!]\r\n) {\r\n CreateFuelTank(\r\n name: $name\r\n coveragePolicy: $coveragePolicy\r\n dispatchRules: [\r\n {\r\n permittedExtrinsics: $permittedExtrinsics #This rule specifies that only batch transfers are subsidized\r\n whitelistedCollections: $whitelistedCollections #This rule ensures that only the specified collection is subsidized\r\n }\r\n ]\r\n ) {\r\n id\r\n method\r\n state\r\n }\r\n}\r\n","variables":{"name":"Collection Token Transfers","coveragePolicy":"FEES","permittedExtrinsics":["BatchTransfer"],"whitelistedCollections":[36105]}}'
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") // Set the name of the fuel tank
.SetCoveragePolicy(CoveragePolicy.Fees) // This is set to FEES since we only want to subsidize transaction fees, and we don't need to provide storage deposits for token transfer transactions
.SetReservesAccountCreationDeposit(null) // This is set to null since we don't want to allow tank account creations
.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));
// Coming Soon!
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!
$coveragePolicy: CoveragePolicy
$permittedExtrinsics: [TransactionMethod!]
$whitelistedCollections: [BigInt!]
) {
CreateFuelTank(
name: $name
coveragePolicy: $coveragePolicy
dispatchRules: [{
permittedExtrinsics: $permittedExtrinsics #This rule specifies that only batch transfers are subsidized
whitelistedCollections: $whitelistedCollections #This rule ensures that only the specified collection is subsidized
}]
){
id
method
state
}
}
`,
variables: {
name: "Collection Token Transfers", //Specify the Fuel Tank name
coveragePolicy: "FEES", //This is set to FEES since we only want to subsidize transaction fees, and we don't need to provide storage deposits for token transfer transactions
permittedExtrinsics: ["BatchTransfer"], //This rule specifies that only batch transfers are subsidized
whitelistedCollections: [36105] //This rule ensures that only the specified collection is subsidized
}
}),
})
.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!
$coveragePolicy: CoveragePolicy
$permittedExtrinsics: [TransactionMethod!]
$whitelistedCollections: [BigInt!]
) {
CreateFuelTank(
name: $name
coveragePolicy: $coveragePolicy
dispatchRules: [{
permittedExtrinsics: $permittedExtrinsics #This rule specifies that only batch transfers are subsidized
whitelistedCollections: $whitelistedCollections #This rule ensures that only the specified collection is subsidized
}]
){
id
method
state
}
}
`,
variables: {
name: "Collection Token Transfers", //Specify the Fuel Tank name
coveragePolicy: "FEES", //This is set to FEES since we only want to subsidize transaction fees, and we don't need to provide storage deposits for token transfer transactions
permittedExtrinsics: ["BatchTransfer"], //This rule specifies that only batch transfers are subsidized
whitelistedCollections: [36105] //This rule ensures that only the specified collection is subsidized
}
}, {
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!
$coveragePolicy: CoveragePolicy
$permittedExtrinsics: [TransactionMethod!]
$whitelistedCollections: [BigInt!]
) {
CreateFuelTank(
name: $name
coveragePolicy: $coveragePolicy
dispatchRules: [{
permittedExtrinsics: $permittedExtrinsics #This rule specifies that only batch transfers are subsidized
whitelistedCollections: $whitelistedCollections #This rule ensures that only the specified collection is subsidized
}]
){
id
method
state
}
}
'''
variables = {
'name': "Collection Token Transfers", #Specify the Fuel Tank name
'coveragePolicy': "FEES", #This is set to FEES since we only want to subsidize transaction fees, and we don't need to provide storage deposits for token transfer transactions
'permittedExtrinsics': ["BatchTransfer"], #This rule specifies that only batch transfers are subsidized
'whitelistedCollections': [36105] #This rule ensures that only the specified collection is subsidized
}
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())
Subsidize Any Transaction Involving MultiTokens From A Certain Collection
Upcoming Feature Notice:
WhitelistedPallets
OptionThe
WhitelistedPallets
argument is not yet supported on the Enjin Platform.
The following code snippet is provided for illustrative purposes only.
If you wish to create a fuel tank with this option now, please use the Enjin Console at console.enjin.io.
We will update the documentation once this option is available.
The following mutation will set up a fuel tank that only subsidizes transactions that involves any token from the collection with ID 36,105. To achieve this, we are using the same dispatch rule from the previous example (whitelistedCollections
) and the WhitelistedPallets
rule, allowing only extrinsics from the MultiTokens
pallet (for actions such as send
, mint
, transfer
, etc.) and Marketplace
pallet (for actions such as list
, buy
, offer
, etc. ).
mutation CreateFuelTank{
CreateFuelTank(
name: "Collection Token Actions" #Specify the Fuel Tank name
coveragePolicy: FEES_AND_DEPOSIT #This is set to FEES_AND_DEPOSIT since we want the tank to provide ENJ for both transaction fees, and storage deposits for transactions that require it (such as listing a token for sale).
reservesAccountCreationDeposit: true #This is set to true since we want to allow tank account creations, and we want the tank to subsidize the ENJ required for the required for the Tank User Account storage deposit
dispatchRules: [{
WhitelistedPallets: [MultiTokens, Marketplace] #This rule specifies that only extrinsics from the MultiTokens and Marketplace pallets are subsidized
whitelistedCollections: [36105] #This rule ensures that only the specified collection is subsidized
}]
){
id
method
state
}
}
curl --location 'https://platform.canary.enjin.io/graphql' \
-H 'Content-Type: application/json' \
-H 'Authorization: enjin_api_key' \
-d '{"query":"mutation CreateFuelTank(\r\n $name: String!\r\n $coveragePolicy: CoveragePolicy\r\n $reserveAccountCreationDeposit: Boolean\r\n $whitelistedPallets: [String!]\r\n $whitelistedCollections: [BigInt!]\r\n) {\r\n CreateFuelTank(\r\n name: $name\r\n coveragePolicy: $coveragePolicy\r\n reservesAccountCreationDeposit: $reserveAccountCreationDeposit\r\n dispatchRules: [\r\n {\r\n whitelistedPallets: $whitelistedPallets\r\n whitelistedCollections: $whitelistedCollections\r\n }\r\n ]\r\n ) {\r\n id\r\n method\r\n state\r\n }\r\n}\r\n","variables":{"name":"Collection Token Actions","coveragePolicy":"FEES_AND_DEPOSIT","reserveAccountCreationDeposit":true,"whitelistedPallets":["MultiTokens","Marketplace"],"whitelistedCollections":[36105]}}'
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()
.SetWhitelistedPallets(Pallets.MultiTokens, Pallets.Marketplace) // Note: This is not yet implemented in the Platform API. This rule specifies that only extrinsics from the MultiTokens and Marketplace pallets are subsidized.
.SetWhitelistedCollections(36105) // This rule ensures that only the specified collection is subsidized.
};
// Setup the mutation
var createFuelTank = new CreateFuelTank()
.SetName("Collection Token Actions") // Set the name of the fuel tank
.SetCoveragePolicy(CoveragePolicy.FeesAndDeposit) // This is set to FEES_AND_DEPOSIT since we want the tank to provide ENJ for both transaction fees, and storage deposits for transactions that require it (such as listing a token for sale).
.SetReservesAccountCreationDeposit(true) // This is set to true since we want to allow tank account creations, and we want the tank to subsidize the ENJ required for the required for the Tank User Account storage deposit.
.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));
// Coming Soon!
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!
$coveragePolicy: CoveragePolicy
$reserveAccountCreationDeposit: Boolean
$whitelistedPallets: [String!]
$whitelistedCollections: [BigInt!]
) {
CreateFuelTank(
name: $name
coveragePolicy: $coveragePolicy
reservesAccountCreationDeposit: $reserveAccountCreationDeposit
dispatchRules: [
{
whitelistedPallets: $whitelistedPallets
whitelistedCollections: $whitelistedCollections
}
]
) {
id
method
state
}
}
`,
variables: {
name: "Collection Token Actions", //Specify the Fuel Tank name
coveragePolicy: "FEES_AND_DEPOSIT", //This is set to FEES_AND_DEPOSIT since we want the tank to provide ENJ for both transaction fees, and storage deposits for transactions that require it (such as listing a token for sale).
reserveAccountCreationDeposit: true, //This is set to true since we want to allow tank account creations, and we want the tank to subsidize the ENJ required for therequired for the Tank User Account storage deposit
whitelistedPallets: ["MultiTokens", "Marketplace"], //This rule specifies that only extrinsics from the MultiTokens and Marketplace pallets are subsidized
whitelistedCollections: [36105] //This rule ensures that only the specified collection is subsidized
}
}),
})
.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!
$coveragePolicy: CoveragePolicy
$reserveAccountCreationDeposit: Boolean
$whitelistedPallets: [String!]
$whitelistedCollections: [BigInt!]
) {
CreateFuelTank(
name: $name
coveragePolicy: $coveragePolicy
reservesAccountCreationDeposit: $reserveAccountCreationDeposit
dispatchRules: [
{
whitelistedPallets: $whitelistedPallets
whitelistedCollections: $whitelistedCollections
}
]
) {
id
method
state
}
}
`,
variables: {
name: "Collection Token Actions", //Specify the Fuel Tank name
coveragePolicy: "FEES_AND_DEPOSIT", //This is set to FEES_AND_DEPOSIT since we want the tank to provide ENJ for both transaction fees, and storage deposits for transactions that require it (such as listing a token for sale).
reserveAccountCreationDeposit: true, //This is set to true since we want to allow tank account creations, and we want the tank to subsidize the ENJ required for therequired for the Tank User Account storage deposit
whitelistedPallets: ["MultiTokens", "Marketplace"], //This rule specifies that only extrinsics from the MultiTokens and Marketplace pallets are subsidized
whitelistedCollections: [36105] //This rule ensures that only the specified collection is subsidized
}
}, {
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!
$coveragePolicy: CoveragePolicy
$reserveAccountCreationDeposit: Boolean
$whitelistedPallets: [String!]
$whitelistedCollections: [BigInt!]
) {
CreateFuelTank(
name: $name
coveragePolicy: $coveragePolicy
reservesAccountCreationDeposit: $reserveAccountCreationDeposit
dispatchRules: [
{
whitelistedPallets: $whitelistedPallets
whitelistedCollections: $whitelistedCollections
}
]
) {
id
method
state
}
}
'''
variables = {
'name': "Collection Token Actions", #Specify the Fuel Tank name
'coveragePolicy': "FEES_AND_DEPOSIT", #This is set to FEES_AND_DEPOSIT since we want the tank to provide ENJ for both transaction fees, and storage deposits for transactions that require it (such as listing a token for sale).
'reserveAccountCreationDeposit': True, #This is set to true since we want to allow tank account creations, and we want the tank to subsidize the ENJ required for therequired for the Tank User Account storage deposit
'whitelistedPallets': ["MultiTokens", "Marketplace"], #This rule specifies that only extrinsics from the MultiTokens and Marketplace pallets are subsidized
'whitelistedCollections': [36105] #This rule ensures that only the specified collection is subsidized
}
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())
Subsidize All Transactions For Whitelisted Accounts With Budget Limitations
The following mutation will set up a fuel tank that subsidizes any transaction, the tank is allowed to subsidize up to 5 ENJ per 30 days for each User Account in the tank, which can be created only if the account is within the whitelisted callers list.
Upcoming Feature Notice:
requireAccount
OptionThe
requireAccount
argument is not yet supported on the Enjin Platform.
The following code snippet is provided for illustrative purposes only.
If you wish to create a fuel tank with this option now, please use the Enjin Console at console.enjin.io.
We will update the documentation once this option is available.
mutation CreateFuelTank{
CreateFuelTank(
name: "Only Specific Accounts Allowed" #Specify the Fuel Tank name
coveragePolicy: FEES_AND_DEPOSIT #This is set to FEES_AND_DEPOSIT since we want the tank to provide ENJ for both transaction fees, and storage deposits for transactions that require it.
accountRules: {
whitelistedCallers: [ #This will validate that the caller is whitelisted at the time of adding the caller's account to the tank's User Accounts.
"cxKy7aqhQTtoJYUjpebxFK2ooKhcvQ2FQj3FePrXhDhd9nLfu",
"cxKRcxyqEuj8qwS4qAmxZMLKNoMJPMhQBLhoQdKekubbo3BtP"
]
}
dispatchRules: [{
requireAccount: true #This is set to true since we want the tank to allow dispatching only if the caller has a User Account in the tank.
userFuelBudget: { #In here we configure how much ENJ to subsidize for each User Account.
amount: 5000000000000000000 #This will allow the tank to subsidize up to 5 ENJ from the Tank's pool per period for each User Account.
resetPeriod: 216000 #This sets the period to 216,000 blocks, which is 30 days on average with 12 seconds average block time. Meaning the tank will be able to subsidize up to 5 ENJ per 30 days for each User Account.
}
}]
){
id
method
state
}
}
curl --location 'https://platform.canary.enjin.io/graphql' \
-H 'Content-Type: application/json' \
-H 'Authorization: enjin_api_key' \
-d '{"query":"mutation CreateFuelTank(\r\n $name: String!\r\n $coveragePolicy: CoveragePolicy\r\n $whitelistedCallers: [String!]\r\n $requireAccount: Boolean\r\n $userFuelBudget: FuelBudgetInputType\r\n) {\r\n CreateFuelTank(\r\n name: $name\r\n coveragePolicy: $coveragePolicy\r\n accountRules: { whitelistedCallers: $whitelistedCallers }\r\n dispatchRules: [\r\n { requireAccount: $requireAccount, userFuelBudget: $userFuelBudget }\r\n ]\r\n ) {\r\n id\r\n method\r\n state\r\n }\r\n}\r\n","variables":{"name":"Only Specific Accounts Allowed","coveragePolicy":"FEES","whitelistedCallers":["cxKy7aqhQTtoJYUjpebxFK2ooKhcvQ2FQj3FePrXhDhd9nLfu","cxKRcxyqEuj8qwS4qAmxZMLKNoMJPMhQBLhoQdKekubbo3BtP"],"requireAccount":true,"userFuelBudget":{"amount":5000000000000000000,"resetPeriod":216000}}}'
using System.Text.Json;
using Enjin.Platform.Sdk;
using Enjin.Platform.Sdk.FuelTanks;
// Create an array of whitelisted callers and assign to accountRules.whitelistedCallers
var whitelistedCallers = new List<string>()
{
"cxKy7aqhQTtoJYUjpebxFK2ooKhcvQ2FQj3FePrXhDhd9nLfu",
"cxKRcxyqEuj8qwS4qAmxZMLKNoMJPMhQBLhoQdKekubbo3BtP"
};
var accountRules = new AccountRuleInputType()
.SetWhitelistedCallers(whitelistedCallers.ToArray());
// Create the user fuel budget input type
var userFuelBudget = new FuelBudgetInputType()
.SetAmount(5000000000000000000) // Set the amount of ENJ that the fuel tank will provide to users.
.SetResetPeriod(216000); // Set the reset period to 216000 blocks (approximately 1 day).
// Create the array of dispatch rules for the fuel tank
var dispatchRules = new List<DispatchRuleInputType>()
{
new DispatchRuleInputType()
.SetRequireAccount(true) // Note: This property has yet to be implemented on the platform. This is set to true since we want the tank to allow dispatching only if the caller has a User Account in the tank.
.SetUserFuelBudget(userFuelBudget) // Set the user fuel budget for the dispatch rule.
};
// Set up the mutation
var createFuelTank = new CreateFuelTank()
.SetName("Only Specific Accounts Allowed") // Set the name of the fuel tank.
.SetCoveragePolicy(CoveragePolicy.FeesAndDeposit) // This is set to FEES_AND_DEPOSIT since we want the tank to provide ENJ for both transaction fees, and storage deposits for transactions that require it (such as listing a token for sale).
.SetAccountRules(accountRules) // Set the account rules for the fuel tank.
.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));
// Coming Soon!
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!
$coveragePolicy: CoveragePolicy
$whitelistedCallers: [String!]
$requireAccount: Boolean
$userFuelBudget: FuelBudgetInputType
) {
CreateFuelTank(
name: $name
coveragePolicy: $coveragePolicy
accountRules: { whitelistedCallers: $whitelistedCallers }
dispatchRules: [
{ requireAccount: $requireAccount, userFuelBudget: $userFuelBudget }
]
) {
id
method
state
}
}
`,
variables: {
name: "Only Specific Accounts Allowed", //Specify the Fuel Tank name
coveragePolicy: "FEES", //This is set to FEES_AND_DEPOSIT since we want the tank to provide ENJ for both transaction fees, and storage deposits for transactions that require it.
whitelistedCallers: [ //This will validate that the caller is whitelisted at the time of adding the caller's account to the tank's User Accounts.
"cxKy7aqhQTtoJYUjpebxFK2ooKhcvQ2FQj3FePrXhDhd9nLfu",
"cxKRcxyqEuj8qwS4qAmxZMLKNoMJPMhQBLhoQdKekubbo3BtP"
],
requireAccount: true, //This is set to true since we want the tank to allow dispatching only if the caller has a User Account in the tank.
userFuelBudget: { //In here we configure how much ENJ to subsidize for each User Account.
amount: 5000000000000000000, //This will allow the tank to subsidize up to 5 ENJ from the Tank's pool per period for each User Account.
resetPeriod: 216000 //This sets the period to 216,000 blocks, which is 30 days on average with 12 seconds average block time. Meaning the tank will be able to subsidize up to 5 ENJ per 30 days for each User Account.
}
}
}),
})
.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!
$coveragePolicy: CoveragePolicy
$whitelistedCallers: [String!]
$requireAccount: Boolean
$userFuelBudget: FuelBudgetInputType
) {
CreateFuelTank(
name: $name
coveragePolicy: $coveragePolicy
accountRules: { whitelistedCallers: $whitelistedCallers }
dispatchRules: [
{ requireAccount: $requireAccount, userFuelBudget: $userFuelBudget }
]
) {
id
method
state
}
}
`,
variables: {
name: "Only Specific Accounts Allowed", //Specify the Fuel Tank name
coveragePolicy: "FEES", //This is set to FEES_AND_DEPOSIT since we want the tank to provide ENJ for both transaction fees, and storage deposits for transactions that require it.
whitelistedCallers: [ //This will validate that the caller is whitelisted at the time of adding the caller's account to the tank's User Accounts.
"cxKy7aqhQTtoJYUjpebxFK2ooKhcvQ2FQj3FePrXhDhd9nLfu",
"cxKRcxyqEuj8qwS4qAmxZMLKNoMJPMhQBLhoQdKekubbo3BtP"
],
requireAccount: true, //This is set to true since we want the tank to allow dispatching only if the caller has a User Account in the tank.
userFuelBudget: { //In here we configure how much ENJ to subsidize for each User Account.
amount: 5000000000000000000, //This will allow the tank to subsidize up to 5 ENJ from the Tank's pool per period for each User Account.
resetPeriod: 216000 //This sets the period to 216,000 blocks, which is 30 days on average with 12 seconds average block time. Meaning the tank will be able to subsidize up to 5 ENJ per 30 days for each User Account.
}
}
}, {
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!
$coveragePolicy: CoveragePolicy
$whitelistedCallers: [String!]
$requireAccount: Boolean
$userFuelBudget: FuelBudgetInputType
) {
CreateFuelTank(
name: $name
coveragePolicy: $coveragePolicy
accountRules: { whitelistedCallers: $whitelistedCallers }
dispatchRules: [
{ requireAccount: $requireAccount, userFuelBudget: $userFuelBudget }
]
) {
id
method
state
}
}
'''
variables = {
'name': "Only Specific Accounts Allowed", #Specify the Fuel Tank name
'coveragePolicy': "FEES", #This is set to FEES_AND_DEPOSIT since we want the tank to provide ENJ for both transaction fees, and storage deposits for transactions that require it.
'whitelistedCallers': [ #This will validate that the caller is whitelisted at the time of adding the caller's account to the tank's User Accounts.
"cxKy7aqhQTtoJYUjpebxFK2ooKhcvQ2FQj3FePrXhDhd9nLfu",
"cxKRcxyqEuj8qwS4qAmxZMLKNoMJPMhQBLhoQdKekubbo3BtP"
],
'requireAccount': True, #This is set to true since we want the tank to allow dispatching only if the caller has a User Account in the tank.
'userFuelBudget': { #In here we configure how much ENJ to subsidize for each User Account.
'amount': 5000000000000000000, #This will allow the tank to subsidize up to 5 ENJ from the Tank's pool per period for each User Account.
'resetPeriod': 216000 #This sets the period to 216,000 blocks, which is 30 days on average with 12 seconds average block time. Meaning the tank will be able to subsidize up to 5 ENJ per 30 days for each User Account.
}
}
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())
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.
Explore More Arguments
For a comprehensive view of all available arguments for queries and mutations, please refer to our API Reference. This resource will guide you on how to use the GraphiQL Playground to explore the full structure and functionality of our API.
Dispatching a Call Using a Fuel Tank
To broadcast a transaction call using a fuel tank, use the Dispatch
/DispatchAndTouch
mutation.
The Fuel Tank requires a UserAccount to dispatch?
Use the
DispatchAndTouch
mutation to create aUserAccount
andDispatch
at the same time in a single transaction.
Not sure which Fuel Tank to select?
If you need help figuring out the best fuel tank to use for a transaction, check out this page: Selecting a fuel tank to dispatch with.
Step #1: Prepare The Mutation
First, prepare the mutation you wish to dispatch, with the id
and encodedData
fields in the response.
In this example, we'll dispatch a call to send a MultiTokenfrom one account to another:
Ask for the
id
andencodedData
fields!Make sure to ask for the
id
andencodedData
fields in the response, or the mutation will fail with an error.
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 Dispatch 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.
variables: null #If the mutation has variables, insert them here.
}
){
id
method
state
}
}
curl --location 'https://platform.canary.enjin.io/graphql' \
-H 'Content-Type: application/json' \
-H 'Authorization: enjin_api_key' \
-d '{"query":"mutation Dispatch(\r\n $tankId: String!\r\n $ruleSetId: BigInt!\r\n $call: DispatchCall!\r\n $query: String!\r\n $variables: Object\r\n) {\r\n Dispatch(\r\n tankId: $tankId\r\n ruleSetId: $ruleSetId\r\n dispatch: { call: $call, query: $query, variables: $variables }\r\n ) {\r\n id\r\n method\r\n state\r\n }\r\n}\r\n","variables":{"tankId":"efQqqMFeDXMSQ43rShznQQ5Aq5pnMUKBfvTQHntatMmF4JZou","ruleSetId":0,"call":"MULTI_TOKENS","query":"mutation TransferNFT{SimpleTransferToken(collectionId: 3298 recipient: \"efQh8FzLm6oH3dmTU3HWqGrtm6Xcuu1WG33N2Ka9fzo5MFFAr\" params: {tokenId: {integer: 1} amount: 1}){id encodedData}}","variables":null}}'
using System.Text.Json;
using Enjin.Platform.Sdk;
using Enjin.Platform.Sdk.FuelTanks;
// Create an array of whitelisted callers and assign to accountRules.whitelistedCallers
var dispatchInput = new DispatchInputType()
.SetCall(DispatchCall.MultiTokens)
.SetQuery("mutation TransferNFT{SimpleTransferToken(collectionId: 3298 recipient: \\\"efQh8FzLm6oH3dmTU3HWqGrtm6Xcuu1WG33N2Ka9fzo5MFFAr\\\" params: {tokenId: {integer: 1} amount: 1}){id encodedData}") // Insert the mutation to dispatch.
.SetVariables(null);
// Set up the mutation
var dispatch = new Dispatch()
.SetTankId("efQqqMFeDXMSQ43rShznQQ5Aq5pnMUKBfvTQHntatMmF4JZou")
.SetRuleSetId(0)
.SetDispatch(dispatchInput);
// Define and assign the return data fragment to the mutation
var transactionFragment = new TransactionFragment()
.WithId()
.WithMethod()
.WithState();
dispatch.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.SendDispatch(dispatch);
Console.WriteLine(JsonSerializer.Serialize(response.Result.Data));
// Coming Soon!
fetch('https://platform.canary.enjin.io/graphql', {
method: 'POST',
headers: {'Content-Type': 'application/json','Authorization': 'Your_Platform_Token_Here'},
body: JSON.stringify({
query: `
mutation Dispatch(
$tankId: String!
$ruleSetId: BigInt!
$call: DispatchCall!
$query: String!
$variables: Object
) {
Dispatch(
tankId: $tankId
ruleSetId: $ruleSetId
dispatch: { call: $call, query: $query, variables: $variables }
) {
id
method
state
}
}
`,
variables: {
tankId: "efQqqMFeDXMSQ43rShznQQ5Aq5pnMUKBfvTQHntatMmF4JZou", //Specify the Fuel Tank ID to dispatch with
ruleSetId: 0, //Specify the ruleset to dispatch with
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.
variables: null //If the mutation has variables, insert them here as an object.
}
}),
})
.then(response => response.json())
.then(data => console.log(data));
const axios = require('axios');
axios.post('https://platform.canary.enjin.io/graphql', {
query: `
mutation Dispatch(
$tankId: String!
$ruleSetId: BigInt!
$call: DispatchCall!
$query: String!
$variables: Object
) {
Dispatch(
tankId: $tankId
ruleSetId: $ruleSetId
dispatch: { call: $call, query: $query, variables: $variables }
) {
id
method
state
}
}
`,
variables: {
tankId: "efQqqMFeDXMSQ43rShznQQ5Aq5pnMUKBfvTQHntatMmF4JZou", //Specify the Fuel Tank ID to dispatch with
ruleSetId: 0, //Specify the ruleset to dispatch with
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.
variables: null //If the mutation has variables, insert them here as an object.
}
}, {
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 Dispatch(
$tankId: String!
$ruleSetId: BigInt!
$call: DispatchCall!
$query: String!
$variables: Object
) {
Dispatch(
tankId: $tankId
ruleSetId: $ruleSetId
dispatch: { call: $call, query: $query, variables: $variables }
) {
id
method
state
}
}
'''
variables = {
'tankId': "efQqqMFeDXMSQ43rShznQQ5Aq5pnMUKBfvTQHntatMmF4JZou", #Specify the Fuel Tank ID to dispatch with
'ruleSetId': 0, #Specify the ruleset to dispatch with
'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.
'variables': None #If the mutation has variables, insert them here as an object.
}
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())
Once the mutation is sent, signed and broadcasted, If the transaction is eligible, the fuel tank will subsidize the transaction fees; otherwise, the transaction will fail.
Updated 21 days ago