If you're building an application on the Avalanche network, you may want to do the transfer programmatically as part of some broader functionality. You can do that by calling the appropriate APIs on an AvalancheGo node. The rest of the tutorial assumes you have access to an AvalancheGo node, AVAX tokens on the X-Chain, and user credentials created and stored in the node's keystore.

All the example API calls below assume the node is running locally (that is, listening on 127.0.0.1). The node can be connected to the main network, a test network or a local network. In each case, the API calls and responses should be the same, except for the address formats. The node need not be local; you can make calls to a node hosted elsewhere.

As you may have noticed while transferring AVAX using the Avalanche Wallet, a cross-chain transfer is a two transaction operation:

  • Export AVAX from the X-Chain

  • Import AVAX to the P-chain

Step 1 - Export AVAX from the X-Chain

To export AVAX, call the X-Chain’s avm.export method with AVAX assetID.

Your call should look like this:

curl -X POST --data '{
"jsonrpc":"2.0",
"id" :1,
"method" :"avm.export",
"params" :{
"to":"P-avax1wkmfja9ve3lt3n9ye4qp3l3gj9k2mz7ep45j7q",
"assetID": "AVAX",
"amount": 5000000,
"changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8",
"username":"myUsername",
"password":"myPassword"
}
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X

where to is the address of a P-Chain address your user controls and changeAddr is the address to send any change to. You can leave changeAddr blank; if you leave it blank, the change will be returned to an address controlled by your user (see here for instructions on creating a new P-Chain address).

Note that you will pay a transaction fee for both the export and import operations. In this example, let’s assume the transaction fee is .001 AVAX. Then, the above export actually consumes .006 AVAX; .005 goes to the P-Chain and .001 is burned as a transaction fee.

Make sure that the amount that you’re sending exceeds the transaction fee. Otherwise, when you import AVAX on the P-Chain, it will consume the transaction fee, and you’ll end up with less AVAX on the P-Chain.

The response should look like this:

{
"jsonrpc": "2.0",
"result": {
"txID": "MqEaeWc4rfkw9fhRMuMTN7KUTNpFmh9Fd7KSre1ZqTsTQG73h",
"changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8"
},
"id": 1
}

We can verify that this transaction was accepted by calling avm.getTxStatus:

curl -X POST --data '{
"jsonrpc": "2.0",
"method": "avm.getTxStatus",
"params":{
"txID":"MqEaeWc4rfkw9fhRMuMTN7KUTNpFmh9Fd7KSre1ZqTsTQG73h"
},
"id": 1
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X

Which shows our transaction is accepted:

{
"jsonrpc": "2.0",
"result": {
"status": "Accepted"
},
"id": 1
}

We can also call avm.getBalance to check that the AVAX was deducted from an address held by our user:

curl -X POST --data '{
"jsonrpc":"2.0",
"id" :1,
"method" :"avm.getBalance",
"params" :{
"address":"X-ADDRESSGOESHERE",
"assetID":"AVAX"
}
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X

The amount deducted is the exported amount (.005 AVAX in this example) plus the transaction fee. If your user controls multiple X-Chain addresses, AVAX may have been sent from any combination of them.

Step 2 - Import AVAX to the P-Chain

Our transfer isn’t done just yet. We need to call the P-Chain’s platform.importAVAX method to finish the transfer.

Your call should look like this:

curl -X POST --data '{
"jsonrpc": "2.0",
"method": "platform.importAVAX",
"params": {
"to":"P-avax1wkmfja9ve3lt3n9ye4qp3l3gj9k2mz7ep45j7q",
"sourceChain":"X",
"changeAddr":"P-avax103y30cxeulkjfe3kwfnpt432ylmnxux8r73r8u",
"username":"myUsername",
"password":"myPassword",
},
"id": 1
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P

This returns the transaction ID:

{
"jsonrpc": "2.0",
"result": {
"txID": "2sxo3ySETZ4xzXqAtgsUvZ5pdkqG4SML4c7Z7NoKLZcp77YNXC",
"changeAddr":"P-avax103y30cxeulkjfe3kwfnpt432ylmnxux8r73r8u"
},
"id": 1
}

We can check that the transaction was accepted with:

curl -X POST --data '{
"jsonrpc":"2.0",
"id" :1,
"method" :"platform.getTxStatus",
"params" :{
"txID":"2sxo3ySETZ4xzXqAtgsUvZ5pdkqG4SML4c7Z7NoKLZcp77YNXC"
}
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P

It should be Committed, meaning the transfer is complete. We can also check the balance of the address with:

curl -X POST --data '{
"jsonrpc": "2.0",
"method": "platform.getBalance",
"params":{
"address":"P-avax1wkmfja9ve3lt3n9ye4qp3l3gj9k2mz7ep45j7q"
},
"id": 1
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P

The response should look like this:

{
"jsonrpc": "2.0",
"result": {
"balance": "4000000",
"utxoIDs": [
{
"txID": "2sxo3ySETZ4xzXqAtgsUvZ5pdkqG4SML4c7Z7NoKLZcp77YNXC",
"outputIndex": 0
}
]
},
"id": 1
}

Note that the balance we see is the amount exported from the X-Chain (.004 AVAX) less the transaction fee (.001 AVAX in this example). Now, we can use the AVAX held by this P-Chain address to provide a stake in order to validate the Primary Network.

Transferring from the P-Chain to X-Chain programmatically

Now, let’s move AVAX from the P-Chain back to the X-Chain.

Same as before, this is also a two transaction operation:

  • Export from the P-Chain

  • Import to the X-Chain

Step 1 - Export AVAX from the P-Chain

To do so, call platform.exportAVAX:

curl -X POST --data '{
"jsonrpc": "2.0",
"method": "platform.exportAVAX",
"params": {
"to":"X-avax1fjn5rffqvny7uk3tjegjs6snwjs3hhgcpcxfax",
"amount":3000000,
"changeAddr":"P-avax103y30cxeulkjfe3kwfnpt432ylmnxux8r73r8u",
"username":"myUsername",
"password":"myPassword"
},
"id": 1
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P

where to is the X-Chain address the AVAX is being sent to.

This returns the transaction ID, and we can check that the transaction was committed with another call to platform.getTxStatus. Again, make sure that the amount you’re sending exceeds the transaction fee.

Step 2 - Import AVAX to X-Chain

To finish our transfer from the P-Chain to the X-Chain, call avm.import:

curl -X POST --data '{
"jsonrpc":"2.0",
"id" :1,
"method" :"avm.import",
"params" :{
"to":"X-avax1fjn5rffqvny7uk3tjegjs6snwjs3hhgcpcxfax",
"sourceChain":"P",
"changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8",
"username":"myUsername",
"password":"myPassword"
}
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X

Note that to is the same address specified in our call to platform.exportAVAX.

Just as before, we can call avm.getBalance to verify the funds were received. The balance should have increased by .003 AVAX minus the transaction fee.

Wrapping Up

That’s it! Now, you can swap AVAX back and forth between the X-Chain and P-Chain, both by using the Avalanche Wallet, and by calling the appropriate API calls on an Avalanche node.

Now you can use the tokens on the P-Chain to add a node as a validator on the Primary Network.


For any additional questions, please visit our knowledge base or contact a support team member via the chat button at support.avax.network.

Chat with Ava Labs | Use Apps on Avalanche | Validate on Avalanche

Build on Avalanche

Did this answer your question?