Transfer asset with GraphQL queries

Before looking at this topic, check out Create action and transaction with GraphQL API first.

You can transfer your assets like NCG, and CRYSTAL with GraphQL queries. At first, let’s send NCG to 0xCbfC996ad185c61a031f40CeeE80a055e6D83005 (If you run this step in mainnet, it will transfer your real money without confirmation. Be careful before proceeding!)

[Optional] Open GraphQL playground

If you prefer to use your GraphQL client of your choice, you can use it. If you not, you can use the GraphQL playground

Create transfer asset action

When you ran the below query:

query {
  actionQuery {
    transferAsset(sender: "0x2cBaDf26574756119cF705289C33710F27443767", recipient: "0xCbfC996ad185c61a031f40CeeE80a055e6D83005", currency: NCG, amount: "10")
  }
}

you can get the action as a hexadecimal string:

{
  "data": {
    "actionQuery": {
      "transferAsset": "6475373a747970655f69647531353a7472616e736665725f61737365743275363a76616c7565736475363a616d6f756e746c647531333a646563696d616c506c61636573313a0275373a6d696e746572736c32303a2c2a05e29e8f57c4661fb8fff5e0c7a7e0f3c4fc6575363a7469636b657275333a4e4347656931303030656575393a726563697069656e7432303acbfc996ad185c61a031f40ceee80a055e6d8300575363a73656e64657232303a2cbadf26574756119cf705289c33710f274437676565"
    }
  },
  "extensions": {}
}

Build unsigned transaction

You can create an unsigned transaction with the action and the transaction nonce. Let’s reference the below GraphQL query:

query {
  transaction {
    unsignedTransaction(publicKey: "0228c66126c62dde22c84cfa55a0578762c95481a81c4b4b2ccf63024b0929bb1b", plainValue: "6475373a747970655f69647531353a7472616e736665725f61737365743275363a76616c7565736475363a616d6f756e746c647531333a646563696d616c506c61636573313a0275373a6d696e746572736c32303a2c2a05e29e8f57c4661fb8fff5e0c7a7e0f3c4fc6575363a7469636b657275333a4e4347656931303030656575393a726563697069656e7432303acbfc996ad185c61a031f40ceee80a055e6d8300575363a73656e64657232303a2cbadf26574756119cf705289c33710f274437676565")
  }
}

Then it will return the unsigned transaction as hexadecimal string:

{
  "data": {
    "transaction": {
      "unsignedTransaction": "64313a616c6475373a747970655f69647531353a7472616e736665725f61737365743275363a76616c7565736475363a616d6f756e746c647531333a646563696d616c506c61636573313a0275373a6d696e746572736c32303a2c2a05e29e8f57c4661fb8fff5e0c7a7e0f3c4fc6575363a7469636b657275333a4e4347656931303030656575393a726563697069656e7432303acbfc996ad185c61a031f40ceee80a055e6d8300575363a73656e64657232303a2cbadf26574756119cf705289c33710f27443767656565313a6733323a15e07324f162d7f28037dc2ab88439c4103602c204af9052befb8a44249ef1fb313a6e693065313a7036353a0428c66126c62dde22c84cfa55a0578762c95481a81c4b4b2ccf63024b0929bb1bc2ca84f8a4e0bbc164a204bfb86fe38a45af3b86f142585a11d6a03818abe8ca313a7332303a2cbadf26574756119cf705289c33710f27443767313a747532373a323032322d30382d33315431313a31333a34372e3530313831385a313a756c32303a2cbadf26574756119cf705289c33710f2744376732303acbfc996ad185c61a031f40ceee80a055e6d830056565"
    }
  },
  "extensions": {}
}

Sign the unsigned message with planet command

After you’ve done the steps above, you should sign the unsigned transaction. The planet command can sign a transaction with your own private key. Before signing you should write the hexadecimal action as raw bytes to some file

ACTION = "64313a616c6475373a747970655f69647531353a7472616e736665725f61737365743275363a76616c7565736475363a616d6f756e746c647531333a646563696d616c506c61636573313a0275373a6d696e746572736c32303a2c2a05e29e8f57c4661fb8fff5e0c7a7e0f3c4fc6575363a7469636b657275333a4e4347656931303030656575393a726563697069656e7432303acbfc996ad185c61a031f40ceee80a055e6d8300575363a73656e64657232303a2cbadf26574756119cf705289c33710f27443767656565313a6733323a15e07324f162d7f28037dc2ab88439c4103602c204af9052befb8a44249ef1fb313a6e693065313a7036353a0428c66126c62dde22c84cfa55a0578762c95481a81c4b4b2ccf63024b0929bb1bc2ca84f8a4e0bbc164a204bfb86fe38a45af3b86f142585a11d6a03818abe8ca313a7332303a2cbadf26574756119cf705289c33710f27443767313a747532373a323032322d30382d33315431313a31333a34372e3530313831385a313a756c32303a2cbadf26574756119cf705289c33710f2744376732303acbfc996ad185c61a031f40ceee80a055e6d830056565"

with open('action' , 'wb') as f:
  f.write(bytes.fromhex(ACTION))

If you have xxd installed you can use it to produce the action file as well: echo "HEX HERE" | xxd -r -p > action.

And you should sign and get the signature.

# planet key sign [KEY_ID] [FILE]
$ planet key sign 05d7edd0-a9dc-4ac5-8196-4d9f52a2e8ed action
Passphrase (of 05d7edd0-a9dc-4ac5-8196-4d9f52a2e8ed): ***
30440220776695df391f67b1060d86b97daafee4c3b55e3125a6c5bbd90dc3e6a7ac96f802206725de0ffe35ced15ede5f0adf343b9ac20a7cea386ec219d9ed5493f83f6cdc

Then the 30440220776695df391f67b1060d86b97daafee4c3b55e3125a6c5bbd90dc3e6a7ac96f802206725de0ffe35ced15ede5f0adf343b9ac20a7cea386ec219d9ed5493f83f6cdc is your signature.

If you’re unsure what is your key ID, you can check it via planet key. More information about the planet tool itself can be found at: "planet" : Libplanet tools to help your Libplanet development journey

Complete transaction

Almost finished. You should complete the unsigned transaction with the signature. There is query.transaction.signTransaction(unsignedTransaction: String!, signature: String!) query to achieve it.

query {
  transaction {
    signTransaction(unsignedTransaction: "64313a616c6475373a747970655f69647531353a7472616e736665725f61737365743275363a76616c7565736475363a616d6f756e746c647531333a646563696d616c506c61636573313a0275373a6d696e746572736c32303a2c2a05e29e8f57c4661fb8fff5e0c7a7e0f3c4fc6575363a7469636b657275333a4e4347656931303030656575393a726563697069656e7432303acbfc996ad185c61a031f40ceee80a055e6d8300575363a73656e64657232303a2cbadf26574756119cf705289c33710f27443767656565313a6733323a15e07324f162d7f28037dc2ab88439c4103602c204af9052befb8a44249ef1fb313a6e693065313a7036353a0428c66126c62dde22c84cfa55a0578762c95481a81c4b4b2ccf63024b0929bb1bc2ca84f8a4e0bbc164a204bfb86fe38a45af3b86f142585a11d6a03818abe8ca313a7332303a2cbadf26574756119cf705289c33710f27443767313a747532373a323032322d30382d33315431313a31333a34372e3530313831385a313a756c32303a2cbadf26574756119cf705289c33710f2744376732303acbfc996ad185c61a031f40ceee80a055e6d830056565", signature: "30440220776695df391f67b1060d86b97daafee4c3b55e3125a6c5bbd90dc3e6a7ac96f802206725de0ffe35ced15ede5f0adf343b9ac20a7cea386ec219d9ed5493f83f6cdc")
  }
}

Then it returns the complete transaction :tada:

Broadcast your transaction

It’s the last step. You should broadcast your transaction through P2P network. There is mutation.stageTransaction mutation to broadcast transaction easily.

mutation {
  stageTransaction(payload: "64313a5337303a30440220776695df391f67b1060d86b97daafee4c3b55e3125a6c5bbd90dc3e6a7ac96f802206725de0ffe35ced15ede5f0adf343b9ac20a7cea386ec219d9ed5493f83f6cdc313a616c6475373a747970655f69647531353a7472616e736665725f61737365743275363a76616c7565736475363a616d6f756e746c647531333a646563696d616c506c61636573313a0275373a6d696e746572736c32303a2c2a05e29e8f57c4661fb8fff5e0c7a7e0f3c4fc6575363a7469636b657275333a4e4347656931303030656575393a726563697069656e7432303acbfc996ad185c61a031f40ceee80a055e6d8300575363a73656e64657232303a2cbadf26574756119cf705289c33710f27443767656565313a6733323a15e07324f162d7f28037dc2ab88439c4103602c204af9052befb8a44249ef1fb313a6e693065313a7036353a0428c66126c62dde22c84cfa55a0578762c95481a81c4b4b2ccf63024b0929bb1bc2ca84f8a4e0bbc164a204bfb86fe38a45af3b86f142585a11d6a03818abe8ca313a7332303a2cbadf26574756119cf705289c33710f27443767313a747532373a323032322d30382d33315431313a31333a34372e3530313831385a313a756c32303a2cbadf26574756119cf705289c33710f2744376732303acbfc996ad185c61a031f40ceee80a055e6d830056565")
}

Then it will return the transaction’s id.

{
  "data": {
    "stageTransaction": "415a008c5c64119a7ed64f2f6173568c76364d2f8bbd22accc7fb59357d93777"
  },
  "extensions": {}
}

[Optional] Check the transaction’s status

You may want to see the transaction was applied to the chain well. There is query.transaction.transactionResult(txId: TxId!) query to see the transaction’s status.

While writing this topic, it was already applied but it will show also STAGING or else.

query {
  transaction {
    transactionResult(txId: "415a008c5c64119a7ed64f2f6173568c76364d2f8bbd22accc7fb59357d93777") {
      txStatus      
    }
  }
}
{
  "data": {
    "transaction": {
      "transactionResult": {
        "txStatus": "SUCCESS"
      }
    }
  },
  "extensions": {}
}
2 Likes

can you please define “Asset”? because if this true, you can also transfer the arena tickets, event tickets, boss fight tickets … that you bought

Arena tickets, Event tickets, Boss fight tickets are not considered as ‘Currency’ in current code.
NCG, CRYSTAL are defined as Currency in libplanet level, which is a transferrable asset with this query, but tickets are considered samely as AP, Prosperity. which is more like assigned value to specific avatar.

1 Like

where we can see all list of current currencies? also if this FAV can we convert the game items so we can transfer it too?

It’s… um. I separately answer 2 questions, that,

  1. Where we can see all list of current currencies?
    It’s defined in Headless GraphTypes.
    NineChronicles.Headless/CurrencyEnumType.cs at 067f19dea1241cf58c77484a57041f041dbe3b31 · planetarium/NineChronicles.Headless · GitHub

  2. if this FAV, can we convert the game items so we can transfer it too?
    I think that’s unlikely. It’s very complicated to explain why, but in simple version creating tickers like ‘FRIEDEGG’ for every single fungible item is um… weird isn’t it?

how to find publicKey?

@fs1507 I left a comment here

1 Like