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:
- Some Enjin Coin on Enjin Matrixchain to pay for Transaction Fees and a deposit of 0.01 ENJ is required for the Token Account Deposit, for each new token holder.
You can obtain cENJ (Canary ENJ) for testing from the Canary faucet.- An Enjin Platform Account.
- A Collection and a Token to mint.
There are two ways to transfer a token:
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.
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, theamount
argument is denoted inu128
. 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, anamount
of5000000000000000000
will actually send 5 ENJ. Keep this in mind when specifying theamount
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 thesigningAccount
argument.
Proceed to the Distributing Tokens via QR tutorial to learn more.
Distribute tokens to your players, even if they don't have wallets!
Updated about 2 months ago