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

🚧

Keep Alive: False

When transferring tokens you've created using the Enjin Platform, always set keepAlive to False.

This flag only relates to your Enjin Coin balance and has no impact on any other token on the network.

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 -X POST "https://platform.enjin.io/graphql" \
  -H "Content-Type: application/json" \
  -H "Authorization: enjin_api_key" \
  -d '{"query": "mutation TransferToken { SimpleTransferToken(collectionId: 36105, recipient: \"cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f\", params: { tokenId: {integer: 0}, amount: 1 }) { id method state } }"}'
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, we use the TransferBalance mutation:

mutation TransferENJTokens {
  TransferBalance(
    recipient: "cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f" #Specify the recipent address
    amount: 5000000000000000000 #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
    method
    state
  }
}
curl -X POST "https://platform.enjin.io/graphql" \
  -H "Content-Type: application/json" \
  -H "Authorization: enjin_api_key" \
  -d '{"query": "mutation TransferENJTokens { TransferBalance(recipient: \"cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f\", amount: 5000000000000000000, keepAlive: true) { id method state } }"}'
Work In Progress
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 TransferENJTokens(
        $recipient: String!
        $amount: BigInt!
        $keep_alive: Boolean
      ) {
        TransferBalance(
          recipient: $recipient
          amount: $amount
          keepAlive: $keep_alive
        ){
          id
          method
          state
        }
      }
    `,
    variables: {
      recipient: "cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f", //Specify the recipent address
      amount: 1, //Specify the amount of tokens to transfer
      keep_alive: 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 TransferENJTokens(
        $recipient: String!
        $amount: BigInt!
        $keep_alive: Boolean
      ) {
        TransferBalance(
          recipient: $recipient
          amount: $amount
          keepAlive: $keep_alive
        ){
          id
          method
          state
        }
      }
  `,
  variables: {
    recipient: "cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f", //Specify the recipent address
    amount: 1, //Specify the amount of tokens to transfer
    keep_alive: 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 TransferENJTokens(
  $recipient: String!
  $amount: BigInt!
  $keep_alive: Boolean
) {
  TransferBalance(
    recipient: $recipient
    amount: $amount
    keepAlive: $keep_alive
  ){
    id
    method
    state
  }
}
'''

variables = {
  'recipient': "cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f", #Specify the recipent address
  'amount': 1, #Specify the amount of tokens to transfer
  'keep_alive': 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())

📘

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

📘

More Fields and Arguments Available!

While the examples here cover the core functionalities of the SimpleTransferToken mutation, there are a few more settings you can adjust.

To view and understand all the available settings for the SimpleTransferToken mutation, refer to our GraphQL Schema on Apollo.

This resource will guide you in tailoring the SimpleTransferToken mutation to your specific requirements.

For instance, by setting the keepAlive argument to true, you ensure that the sender's token count won't drop to zero. This could be useful in very specific scenarios. For example, when a player sends a token representing a key, and all users must have at least one key at all times.

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 -X POST "https://platform.enjin.io/graphql" \
  -H "Content-Type: application/json" \
  -H "Authorization: enjin_api_key" \
  -d '{"query": "mutation BatchSendENJ { BatchTransferBalance(recipients: [{ account: \"cxLU94nRz1en6gHnXnYPyTdtcZZ9dqBasexvexjArj4V1Qr8f\", transferBalanceParams: { value: 5000000000000000000 } }, { account: \"cxKy7aqhQTtoJYUjpebxFK2ooKhcvQ2FQj3FePrXhDhd9nLfu\", transferBalanceParams: { value: 15250000000000000000, keepAlive: true } }]) { id transactionId state } }"}'
Work In Progress
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.

👍

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

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