Transferring Tokens

Start moving tokens between wallets.

You will need to transfer tokens for:

  • Implementing various gameplay features such as gifting, trading, and rewards.
  • Supporting secure and efficient token transactions.
  • Providing a seamless user experience by allowing token transfers without leaving the game environment.

📘

What you'll need:

There are two ways to transfer a token:

  1. Using the Platform User Interface
  2. Using the GraphQL API

Option A. Using the Enjin Dashboard

In the Platform menu, navigate to "Tokens".
Locate the token you wish to transfer, click the 3 vertical dots () to it's right, then click the "Transfer" button.

📘

Need to perform multiple transfers?

Click on the "Batch" button, followed by "Batch Transfer".

Fill in the recipient, amount, and other optional arguments in the corresponding fields.
Once you're satisfied with the options, click on the "Transfer" button at the bottom right corner to create the request.

Transfer Token form on Enjin Platform

Transfer Token form on Enjin Platform

A notification appears after you create a <<glossary:Mutation>>.

A notification appears after you create a Mutation.

Clicking "**View**" on the notification will take you to your Transactions List.

Clicking "View" on the notification will take you to your Transactions List.

Since this transaction is a Mutation, you will need to sign the transaction using your Wallet.

  • If a Wallet Daemon is running and configured, the transaction request will be signed automatically.
  • If a wallet is connected such as the Enjin Wallet or Polkadot.js, the transaction must be signed manually by clicking the "Sign" button and approving the signature request in your wallet.

If you're looking to distribute tokens to your community or players, but don't have their account addresses, don't worry! Our solution is Enjin Beam.
Proceed to the Distributing Tokens via QR tutorial to learn more.

Option B. Using the Enjin API & SDKs

Transferring an asset

SimpleTransferToken mutation simplifies the process of transferring a specific token from one wallet to another. It is a straightforward way to facilitate token transfers without the need for complex intermediary steps.

mutation TransferToken{
  SimpleTransferToken(
    collectionId: 36105 #Specify the collection ID
    recipient: "cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f" #Specify the recipent address
    params: {
      tokenId: {integer: 0} #Specify the token ID
      amount: 1 #Choose the transfer amount
    }
  ){
    id
    method
    state
  }
}
curl --location 'https://platform.canary.enjin.io/graphql' \
-H 'Content-Type: application/json' \
-H 'Authorization: enjin_api_key' \
-d '{"query":"mutation TransferToken(\r\n  $collection_id: BigInt!\r\n  $token_id: BigInt!\r\n  $recipient: String!\r\n  $amount: BigInt!\r\n) {\r\n  SimpleTransferToken(\r\n    collectionId: $collection_id\r\n    recipient: $recipient\r\n    params: { tokenId: { integer: $token_id }, amount: $amount }\r\n  ) {\r\n    id\r\n    method\r\n    state\r\n  }\r\n}\r\n","variables":{"collection_id":36105,"token_id":0,"recipient":"cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f","amount":1}}'
using System.Text.Json;
using Enjin.Platform.Sdk;

// Define the simple transfer parameters
var simpleTransferParams = new SimpleTransferParams()
    .SetTokenId(new EncodableTokenIdInput().SetInteger(0))
    .SetAmount(1);


// Setup the mutation
var simpleTransferToken = new SimpleTransferToken()
  	.SetRecipient("cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f")
    .SetCollectionId(36105)
    .SetParams(simpleTransferParams);

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

simpleTransferToken.Fragment(simpleTransferTokenFragment);

// 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.SendSimpleTransferToken(simpleTransferToken);
Console.WriteLine(JsonSerializer.Serialize(response.Result.Data));
#include "EnjinPlatformSdk/CoreMutations.hpp"
#include <iostream>

using namespace enjin::platform::sdk;
using namespace std;

int main() {

    // Define the simple transfer params
    shared_ptr tokenId = make_shared<EncodableTokenIdInput>();
    tokenId->SetInteger(make_shared<SerializableString>("0"));

    SimpleTransferParams simpleTransferParams = SimpleTransferParams()
            .SetAmount(make_shared<SerializableString>("1"))
            .SetTokenId(tokenId);

    // Setup mutation
    SimpleTransferToken simpleTransferToken = SimpleTransferToken()
            .SetRecipient(make_shared<SerializableString>("cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f"))
            .SetCollectionId(make_shared<SerializableString>("36105"))
            .SetParams(make_shared<SimpleTransferParams>(simpleTransferParams));

    // Define and assign the return data fragment to the mutation
    shared_ptr<TransactionFragment> transactionFragment = make_shared<TransactionFragment>();
    transactionFragment
        ->WithId()
        .WithMethod()
        .WithState();

    simpleTransferToken.SetFragment(transactionFragment);

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

    // Send the request then get the response 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.
    future<shared_ptr<IPlatformResponse<GraphQlResponse<Transaction>>>> futureResponse = SendSimpleTransferToken(*client, simpleTransferToken);

    // Get the platform response holding the HTTP data
    PlatformResponsePtr<GraphQlResponse<Transaction>> response = futureResponse.get();

    // Get the result, a GraphQL response, holding the GraphQL data
    const optional<GraphQlResponse<Transaction>>& gqlResult = response->GetResult();

    // Write the result data to the console
    if (gqlResult.has_value() && gqlResult->IsSuccess())
    {
        const optional<Transaction>& transaction = gqlResult->GetData()->GetResult();

        std::cout << to_string(transaction->GetId().value()) << std::endl;
        std::cout << ToString(transaction->GetMethod().value()) << std::endl;
    }

    // Write any error messages to the console
    if (gqlResult.has_value() && gqlResult->HasErrors())
    {
        const optional<vector<GraphQlError>>& errors = gqlResult->GetErrors();

        for (const GraphQlError& error : errors.value()) {
            std::cout << error.GetMessage().value() << std::endl;
        }
    }

    client.reset();

    return 0;
}

fetch('https://platform.canary.enjin.io/graphql', {
  method: 'POST',
  headers: {'Content-Type': 'application/json','Authorization': 'Your_Platform_Token_Here'},
  body: JSON.stringify({
    query: `
      mutation TransferToken(
        $collection_id: BigInt!
        $token_id: BigInt!
        $recipient: String!
        $amount: BigInt!
      ) {
        SimpleTransferToken(
          collectionId: $collection_id
          recipient: $recipient
          params: {
            tokenId: {integer: $token_id}
            amount: $amount
          }
        ){
          id
          method
          state
        }
      }
    `,
    variables: {
      collection_id: 36105, //Specify the collection ID
      token_id: 0, //Specify the token ID
      recipient: "cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f", //Specify the recipent address
      amount: 1 //Choose the transfer amount
    }
  }),
})
.then(response => response.json())
.then(data => console.log(data));
const axios = require('axios');

axios.post('https://platform.canary.enjin.io/graphql', {
  query: `
    mutation TransferToken(
      $collection_id: BigInt!
      $token_id: BigInt!
      $recipient: String!
      $amount: BigInt!
    ) {
      SimpleTransferToken(
        collectionId: $collection_id
        recipient: $recipient
        params: {
          tokenId: {integer: $token_id}
          amount: $amount
        }
      ){
        id
        method
        state
      }
    }
  `,
  variables: {
    collection_id: 36105, //Specify the collection ID
    token_id: 0, //Specify the token ID
    recipient: "cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f", //Specify the recipent address
    amount: 1 //Choose the transfer amount
  }
}, {
  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 TransferToken(
  $collection_id: BigInt!
  $token_id: BigInt!
  $recipient: String!
  $amount: BigInt!
) {
  SimpleTransferToken(
    collectionId: $collection_id
    recipient: $recipient
    params: {
      tokenId: {integer: $token_id}
      amount: $amount
    }
  ){
    id
    method
    state
  }
}
'''

variables = {
  'collection_id': 36105, #Specify the collection ID
  'token_id': 0, #Specify the token ID
  'recipient': "cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f", #Specify the recipent address
  'amount': 1 #Choose the transfer amount
}

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())

Transferring ENJ token

To send ENJ / CENJ tokens from one wallet to another, use the TransferAllowDeath mutation, or the TransferKeepAlive if you want to make sure the account doesn't get reaped (Read more about account reaping):

mutation TransferENJTokens {
  TransferKeepAlive(
    recipient: "cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f" #Specify the recipent address
    amount: 5000000000000000000 #Specify the amount of tokens to transfer
  ) {
    id
    method
    state
  }
}
curl --location 'https://platform.canary.enjin.io/graphql' \
-H 'Content-Type: application/json' \
-H 'Authorization: enjin_api_key' \
-d '{"query":"mutation TransferENJTokens(\r\n  $recipient: String!\r\n  $amount: BigInt!\r\n  $keep_alive: Boolean\r\n) {\r\n  TransferBalance(\r\n    recipient: $recipient\r\n    amount: $amount\r\n    keepAlive: $keep_alive\r\n  ) {\r\n    id\r\n    method\r\n    state\r\n  }\r\n}\r\n","variables":{"recipient":"cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f","amount":1,"keep_alive":true}}'
using System.Text.Json;
using Enjin.Platform.Sdk;

// Set up the mutation
var transferKeepAlive = new TransferKeepAlive()
    .SetRecipient("cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f") //The recipient of the initial supply
    .SetAmount(5000000000000000000); //The amount of tokens to transfer

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

transferKeepAlive.Fragment(transferKeepAliveFragment);

// 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.SendTransferKeepAlive(transferKeepAlive);
Console.WriteLine(JsonSerializer.Serialize(response.Result.Data));
Work In Progress
fetch('https://platform.canary.enjin.io/graphql', {
  method: 'POST',
  headers: {'Content-Type': 'application/json','Authorization': 'Your_Platform_Token_Here'},
  body: JSON.stringify({
    query: `
      mutation TransferKeepAlive(
        $recipient: String!
        $amount: BigInt!
      ) {
        TransferBalance(
          recipient: $recipient
          amount: $amount
        ){
          id
          method
          state
        }
      }
    `,
    variables: {
      recipient: "cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f", //Specify the recipent address
      amount: 1 //Specify the amount of tokens to transfer
    }
  }),
})
.then(response => response.json())
.then(data => console.log(data));
const axios = require('axios');

axios.post('https://platform.canary.enjin.io/graphql', {
  query: `
    mutation TransferKeepAlive(
        $recipient: String!
        $amount: BigInt!
      ) {
        TransferBalance(
          recipient: $recipient
          amount: $amount
        ){
          id
          method
          state
        }
      }
  `,
  variables: {
    recipient: "cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f", //Specify the recipent address
    amount: 1 //Specify the amount of tokens to transfer
  }
}, {
  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 TransferKeepAlive(
  $recipient: String!
  $amount: BigInt!
) {
  TransferBalance(
    recipient: $recipient
    amount: $amount
  ){
    id
    method
    state
  }
}
'''

variables = {
  'recipient': "cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f", #Specify the recipent address
  'amount': 1 #Specify the amount of tokens to transfer
  
}

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())

📘

Notes:

  • amount argument
    • In the TransferBalance mutation, the amount argument is denoted in u128. This means that the number you specify is divided by 10^18 to determine the actual amount of ENJ to be transferred.
      In the example above, an amount of 5000000000000000000 will actually send 5 ENJ. Keep this in mind when specifying the amount in your mutations.
  • keepAlive argument
    • Set to true if you want to make sure the account doesn't get reaped.
      Learn more about keepAlive argument here

Batch Transferring ENJ token

To send ENJ / CENJ tokens from one wallet to multiple addresses or in multiple transactions, we use the BatchTransferBalance mutation

mutation BatchSendENJ{
  BatchTransferBalance(
    recipients: [
      {
        account: "cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f", #Specify the recipent address
        transferBalanceParams: {
          value: 5000000000000000000 #Specify the amount of tokens to transfer
        }
      },
      {
        account: "cxKy7aqhQTtoJYUjpebxFK2ooKhcvQ2FQj3FePrXhDhd9nLfu", #Specify the recipent address
        transferBalanceParams: {
          value: 15250000000000000000 #Specify the amount of tokens to transfer
          keepAlive: true #Set to true if you want to make sure the account doesn't get reaped
        }
      },
    ]
  ){
    id
    transactionId
    state
  }
}
curl --location 'https://platform.canary.enjin.io/graphql' \
-H 'Content-Type: application/json' \
-H 'Authorization: enjin_api_key' \
-d '{"query":"mutation BatchSendENJ($recipients: [TransferRecipient!]!) {\r\n  BatchTransferBalance(recipients: $recipients) {\r\n    id\r\n    transactionId\r\n    state\r\n  }\r\n}\r\n","variables":{"recipients":[{"account":"cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f","transferBalanceParams":{"value":5000000000000000000}},{"account":"cxKy7aqhQTtoJYUjpebxFK2ooKhcvQ2FQj3FePrXhDhd9nLfu","transferBalanceParams":{"value":15250000000000000000,"keepAlive":true}}]}}'
using System.Text.Json;
using Enjin.Platform.Sdk;

// Set up the transfers for the batch
var transferBalanceParams1 = new TransferBalanceParams()
    .SetValue(5000000000000000000); //The amount of tokens to transfer

var transferBalanceParams2 = new TransferBalanceParams()
    .SetValue(5000000000000000000) //The amount of tokens to transfer
    .SetKeepAlive(true); //Whether the transaction will be kept from failing if the balance drops below the minimum requirement

var transferRecipients = new[]
{
    new TransferRecipient()
        .SetAccount("cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f")
        .SetTransferBalanceParams(transferBalanceParams1),
    new TransferRecipient()
        .SetAccount("cxKy7aqhQTtoJYUjpebxFK2ooKhcvQ2FQj3FePrXhDhd9nLfu")
        .SetTransferBalanceParams(transferBalanceParams2)
};

// Set up the mutation
var batchTransferBalance = new BatchTransferBalance()
    .SetRecipients(transferRecipients);

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

batchTransferBalance.Fragment(transferBalanceFragment);

// 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.SendBatchTransferBalance(batchTransferBalance);
Console.WriteLine(JsonSerializer.Serialize(response.Result.Data));
Work In Progress
fetch('https://platform.canary.enjin.io/graphql', {
  method: 'POST',
  headers: {'Content-Type': 'application/json','Authorization': 'Your_Platform_Token_Here'},
  body: JSON.stringify({
    query: `
      mutation BatchSendENJ($recipients: [TransferRecipient!]!){
        BatchTransferBalance(
          recipients: $recipients
        ){
          id
          transactionId
          state
        }
      }
    `,
    variables: {
  		recipients:[
        {
          account: "cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f", //Specify the recipent address
          transferBalanceParams: { value: 5000000000000000000 } //Specify the amount of tokens to transfer
        },
        {
          account: "cxKy7aqhQTtoJYUjpebxFK2ooKhcvQ2FQj3FePrXhDhd9nLfu", //Specify the recipent address
          transferBalanceParams: {
            value: 15250000000000000000, //Specify the amount of tokens to transfer
            keepAlive: true //Set to true if you want to make sure the account doesn't get reaped
          }
        }
      ]
    }
  }),
})
.then(response => response.json())
.then(data => console.log(data));
const axios = require('axios');

axios.post('https://platform.canary.enjin.io/graphql', {
  query: `
    mutation BatchSendENJ($recipients: [TransferRecipient!]!){
        BatchTransferBalance(
          recipients: $recipients
        ){
          id
          transactionId
          state
        }
      }
  `,
  variables: {
    recipients:[
      {
        account: "cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f", //Specify the recipent address
        transferBalanceParams: { value: 5000000000000000000 } //Specify the amount of tokens to transfer
      },
      {
        account: "cxKy7aqhQTtoJYUjpebxFK2ooKhcvQ2FQj3FePrXhDhd9nLfu", //Specify the recipent address
        transferBalanceParams: {
          value: 15250000000000000000, //Specify the amount of tokens to transfer
          keepAlive: true //Set to true if you want to make sure the account doesn't get reaped
        }
      }
    ]
  }
}, {
  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 BatchSendENJ($recipients: [TransferRecipient!]!){
  BatchTransferBalance(
    recipients: $recipients
  ){
    id
    transactionId
    state
  }
}
'''

variables = {
  'recipients':[
    {
      'account': "cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f", #Specify the recipent address
      'transferBalanceParams': { 'value': 5000000000000000000 } #Specify the amount of tokens to transfer
    },
    {
      'account': "cxKy7aqhQTtoJYUjpebxFK2ooKhcvQ2FQj3FePrXhDhd9nLfu", #Specify the recipent address
      'transferBalanceParams': {
        'value': 15250000000000000000, #Specify the amount of tokens to transfer
        'keepAlive': True #Set to true if you want to make sure the account doesn't get reaped
      }
    }
  ]
}

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 transfer transaction in real time by listening to the app channel on the WebSocket.

📘

Need to send a transaction request to user's wallet?

This can be done using Enjin Platform API & WalletConnect!
To learn more, check out the Using WalletConnect page.

📘

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.

For instance, you'll find settings such as continueOnFailure to skip data that would cause the whole batch to fail, or the ability to sign using a managed wallet with the signingAccount argument.

👍

Proceed to the Distributing Tokens via QR tutorial to learn more.

Distribute tokens to your players, even if they don't have wallets!