5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Using the Coinbase Mesh API with Symbol and NEM Blockchain

Posted at

Introduction

Imagine a scenario where you're tasked with building integrations across five different blockchain networks in just a week—an overwhelming challenge for developers. This is where the Coinbase Mesh API becomes invaluable. It provides developers with a standardized way to interact with different blockchains, making it easier and quicker to integrate than building custom apps for each blockchain. The Mesh API provides endpoints for creating and submitting transactions, checking account balances, and retrieving block details.

The Mesh API treats each balance change as a single operation in the blockchain. It uses these operations to describe all events that change balances on the network. For a transfer transaction, one operation deducts from the sender’s account, and another adds to the recipient’s account.

This guide shows you how to create and send a transfer transaction using the Mesh APIs. The aim is for any app, like a wallet or explorer, that supports the Mesh API to work with any blockchain that uses it.

Enable Mesh APIs

The Mesh API is built into the Symbol REST component for both Symbol and NEM blockchains. To enable Mesh APIs in Symbol REST, edit the rest.json file and add the route extension for your blockchain. Use symbolRosetta for Symbol and nemRosetta for NEM.

Before you start, ensure you have the required version of Symbol REST v2.5.1.

Symbol Setup

You can set up the MESH API in Symbol in two ways.

  1. Enable MESH API on a Symbol Node
  2. Enable MESH API in a standalone Symbol Rest Service.

Here is an example of what to add to the rest.json file for the Symbol Node.

 "routeExtensions": [
  "symbolRosetta"
 ],
 "rosetta": {
  "aggregateSignerPrivateKey": "SymbolAccountPrivateKey"
 }

After you restart the REST service, the Mesh API will be ready to use.

Note: aggregateSignerPrivateKey is the private key used to sign the aggregate transaction; it is required only for Symbol.

Note: For the standalone Symbol Rest Service, add the restEndpoint to point to the Symbol Node.

NEM Setup

Here is an example of what to add to the Symbol REST configuration file (rest.json) for NEM.

  "restEndpoint": "http://<NEM Node>:7890",
  "routeExtensions": [
    "nemRosetta"
  ]

In the NEM node configuration, update the properties file with the following:

  1. The Symbol REST node uses local NEM APIs. Set nis.additionalLocalIps to your REST Node IP
  2. The Mesh APIs need to track expired mosaics. Set nis.optionalFeatures to TRANSACTION_HASH_LOOKUP|TRACK_EXPIRED_MOSAICS

Start the Symbol REST service by running: npm run start-rosetta /rest.json

Creating a transfer transaction

Symbol and NEM blockchains both support JavaScript and Python, and they offer SDKs to help you create and send transactions. But what if you use a different programming language? Do you need to build a new SDK to send a transfer transaction?

With the Symbol Mesh API, you can build a transfer transaction using the Mesh Construction APIs. All examples here use curl on the testnet server so that you can follow along step by step.

Note: The current implementation of the Mesh API only supports transferring the native currency (XYM or XEM).

Step 1: Fetch Network Information

Before creating a transaction, retrieve information about supported networks to ensure you’re using the correct NetworkIdentifier for subsequent requests.

Endpoint

  • Path: /network/list
  • Method: POST
  • Required Parameters:
    • None
curl -s -X POST "https://201-sai-dual.symboltest.net:3001/network/list" \
-H "Content-Type: application/json"  | jq 
{
  "network_identifiers": [
    {
      "blockchain": "Symbol",
      "network": "testnet"
    }
  ]
}

Step 2: Preprocess Transaction Parameters

Use the /construction/preprocess endpoint to set the main transaction details. Operation objects show the sender, recipient, and transfer amount.

Endpoint

  • Path: /construction/preprocess
  • Method: POST
  • Required Parameters:
    • NetworkIdentifier: The blockchain network.
    • Operations: Describe the intent of the transaction, including sender/receiver information and amounts.

Preprocessing identifies which public keys are needed for the payload request.

curl -s -X POST "https://201-sai-dual.symboltest.net:3001/construction/preprocess" \
-H "Content-Type: application/json" \
-d '{
  "network_identifier": {
    "blockchain": "Symbol",
    "network": "testnet"
  },
  "operations": [
    {
      "operation_identifier": { "index": 0 },
      "type": "transfer",
      "account": { "address": "TCGK56TPAMEIB2EGRJGNJ66INLGVPJ7EO436LEQ" },
      "amount": { "value": "-100000", "currency": { "symbol": "symbol.xym", "decimals": 6 } }
    },
    {
      "operation_identifier": { "index": 1 },
      "type": "transfer",
      "account": { "address": "TCSQ4QFFX75JKC4K4X73WP5KFDHBRE3LRCMJSAQ" },
      "amount": { "value": "100000", "currency": { "symbol": "symbol.xym", "decimals": 6 } }
    }
  ]
}' | jq
{
  "options": {},
  "required_public_keys": [
    {
      "address": "TCGK56TPAMEIB2EGRJGNJ66INLGVPJ7EO436LEQ"
    }
  ]
}

Step 3: Fetch Metadata

Collect chain-specific data needed to build the transfer transaction.

Endpoint

  • Path: /construction/metadata
  • Method: POST
  • Required Parameters:
    • NetworkIdentifier

This endpoint returns the metadata required to construct the transaction payload.

curl -s -X POST "https://201-sai-dual.symboltest.net:3001/construction/metadata" \                                                 
-H "Content-Type: application/json" \
-d '{
  "network_identifier": {
    "blockchain": "Symbol",
    "network": "testnet"
  } 
}'| jq           
{
  "metadata": {
    "networkTime": "99802433607",
    "feeMultiplier": 100
  }
}

Step 4: Generate Unsigned Transaction

Create an unsigned transaction and signing payloads for the sender using the /construction/payloads endpoint.

Endpoint

  • Path: /construction/payloads
  • Method: POST
  • Required Parameters:
    • Operations: Same as in /construction/preprocess, plus the required public keys.
    • Metadata: Collected from /construction/metadata.

Note: Each operation requires a unique operation_identifier index.

curl -s -X POST "https://201-sai-dual.symboltest.net:3001/construction/payloads" \
-H "Content-Type: application/json" \
-d '{
  "network_identifier": {
    "blockchain": "Symbol",
    "network": "testnet"
  },
  "operations": [
    {
      "operation_identifier": { "index": 0 },                                                                                                                            
      "type": "transfer",
      "account": { "address": "TCGK56TPAMEIB2EGRJGNJ66INLGVPJ7EO436LEQ" },
      "amount": { "value": "-100000", "currency": { "symbol": "symbol.xym", "decimals": 6 } }                                                         
    },
    {                      
      "operation_identifier": { "index": 1 },
      "type": "transfer",                                                            
      "account": { "address": "TCSQ4QFFX75JKC4K4X73WP5KFDHBRE3LRCMJSAQ" },
      "amount": { "value": "100000", "currency": { "symbol": "symbol.xym", "decimals": 6 } }
    }
  ],           
  "metadata": {
    "networkTime": "99802433607",
    "feeMultiplier": 100
  },                                                                                 
  "public_keys": [               
    {
     "hex_bytes": "59DDB32FBD56DE17903F645FC1B0BC70F6B59F41126EE9632978156E91ABD095",
     "curve_type": "edwards25519"
    }
  ]
}' | jq
{
  "unsigned_transaction": "08010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000059DDB32FBD56DE17903F645FC1B0BC70F6B59F41126EE9632978156E91ABD09500000000039841412067000000000000BA4CD43C1700000021A35FB66B04A9AF55558E89317E5B3A54FF0360E89452662935825EB950D89A6000000000000000600000000000000059DDB32FBD56DE17903F645FC1B0BC70F6B59F41126EE9632978156E91ABD095000000000198544198A50E40A5BFFA950B8AE5FFBB3FAA28CE18936B889899020000010000000000EEAFF441BA994BE7A086010000000000",
  "payloads": [
    {
      "hex_bytes": "49D6E1CE276A85B70EAFE52349AACCA389302E7A9754BCF1221E79494FC665A4039841412067000000000000BA4CD43C1700000021A35FB66B04A9AF55558E89317E5B3A54FF0360E89452662935825EB950D89A60000000",
      "account_identifier": {
        "address": "TCGK56TPAMEIB2EGRJGNJ66INLGVPJ7EO436LEQ"
      },
      "signature_type": "ed25519"
    }
  ]
}

Step 5: Sign the Transaction

Take the payloads from the last step and sign the transaction using the sender’s private key.

In the example below, I used the Symbol Python SDK to sign the payloads.hex_bytes from the previous step.

Python Example

from binascii import unhexlify
from symbolchain.symbol.KeyPair import KeyPair
from symbolchain.CryptoTypes import PrivateKey

key_pair = KeyPair(PrivateKey('private_key_hex'))
signature = key_pair.sign(unhexlify('49D6E1CE276A85B70EAFE52349AACCA389302E7A9754BCF1221E79494FC665A4039841412067000000000000C736E73C1700000021A35FB66B04A9AF55558E89317E5B3A54FF0360E89452662935825EB950D89A60000000'))
print(f'signature: {signature}')

Step 6: Combine Signatures with Unsigned Transaction

Combine the unsigned transaction and signatures into a signed transaction using /construction/combine.

Endpoint

  • Path: /construction/combine
  • Method: POST
  • Required Parameters:
    • UnsignedTransaction: From /construction/payloads.
    • Signatures: Generated in Step 5.
curl -s -X POST "https://201-sai-dual.symboltest.net:3001/construction/combine" \
-H "Content-Type: application/json" \
-d '{
  "network_identifier": {
    "blockchain": "Symbol",
    "network": "testnet"
  },
  "unsigned_transaction": "08010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000059DDB32FBD56DE17903F645FC1B0BC70F6B59F41126EE9632978156E91ABD09500000000039841412067000000000000C736E73C1700000021A35FB66B04A9AF55558E89317E5B3A54FF0360E89452662935825EB950D89A6000000000000000600000000000000059DDB32FBD56DE17903F645FC1B0BC70F6B59F41126EE9632978156E91ABD095000000000198544198A50E40A5BFFA950B8AE5FFBB3FAA28CE18936B889899020000010000000000EEAFF441BA994BE7A086010000000000",
  "signatures": [
    {
      "hex_bytes": "8D4220BCDDF43FF230DBD865FD1D7BDE68D0BE080565DC3F13564174AA775F44CD7BCF5888538DC11D2E5AA2538C651D708A0181ECEEF1FB4E246F770D68180C",
      "signing_payload": { "hex_bytes": "49D6E1CE276A85B70EAFE52349AACCA389302E7A9754BCF1221E79494FC665A4039841412067000000000000C736E73C1700000021A35FB66B04A9AF55558E89317E5B3A54FF0360E89452662935825EB950D89A60000000" },
      "public_key":     {
     "hex_bytes": "59DDB32FBD56DE17903F645FC1B0BC70F6B59F41126EE9632978156E91ABD095",
     "curve_type": "edwards25519"
    },
      "signature_type": "ed25519"
    }
  ]
}' | jq
{
  "signed_transaction": "08010000000000008D4220BCDDF43FF230DBD865FD1D7BDE68D0BE080565DC3F13564174AA775F44CD7BCF5888538DC11D2E5AA2538C651D708A0181ECEEF1FB4E246F770D68180C59DDB32FBD56DE17903F645FC1B0BC70F6B59F41126EE9632978156E91ABD09500000000039841412067000000000000C736E73C1700000021A35FB66B04A9AF55558E89317E5B3A54FF0360E89452662935825EB950D89A6000000000000000600000000000000059DDB32FBD56DE17903F645FC1B0BC70F6B59F41126EE9632978156E91ABD095000000000198544198A50E40A5BFFA950B8AE5FFBB3FAA28CE18936B889899020000010000000000EEAFF441BA994BE7A086010000000000"
}

Step 7: Submit the Transaction

Send the signed transaction to the blockchain using /construction/submit.

Endpoint

  • Path: /construction/submit
  • Method: POST
  • Required Parameters:
    • SignedTransaction: From /construction/combine
curl -s -X POST "https://201-sai-dual.symboltest.net:3001/construction/submit" \
-H "Content-Type: application/json" \
-d '{
  "network_identifier": {
    "blockchain": "Symbol",
    "network": "testnet"
  },
 "signed_transaction": "08010000000000008D4220BCDDF43FF230DBD865FD1D7BDE68D0BE080565DC3F13564174AA775F44CD7BCF5888538DC11D2E5AA2538C651D708A0181ECEEF1FB4E246F770D68180C59DDB32FBD56DE17903F645FC1B0BC70F6B59F41126EE9632978156E91ABD09500000000039841412067000000000000C736E73C1700000021A35FB66B04A9AF55558E89317E5B3A54FF0360E89452662935825EB950D89A6000000000000000600000000000000059DDB32FBD56DE17903F645FC1B0BC70F6B59F41126EE9632978156E91ABD095000000000198544198A50E40A5BFFA950B8AE5FFBB3FAA28CE18936B889899020000010000000000EEAFF441BA994BE7A086010000000000"
}' | jq 
{
  "transaction_identifier":
    {
      "hash":"5D32C48A49292D8918EB08C2595608E747C2090F5764B49C13216E14D7F32E34"
    }
}

Step 8: Verify Transaction

Verify that the transaction was successful using the hash from the previous step.

curl -s https://201-sai-dual.symboltest.net:3001/transactionStatus/5D32C48A49292D8918EB08C2595608E747C2090F5764B49C13216E14D7F32E34 | jq
{
  "group": "confirmed",
  "code": "Success",
  "hash": "5D32C48A49292D8918EB08C2595608E747C2090F5764B49C13216E14D7F32E34",
  "deadline": "99806033607",
  "height": "3000412"
}

Step 9: Get account balance

Retrieve the account balance.

Endpoint

  • Path: /account/balance
  • Method: POST
  • Required Parameters:
    • UnsignedTransaction: From /construction/payloads.
    • Signatures: Generated in Step 5.

Check the destination account balance to confirm the transfer succeeded.

curl -s -X POST "https://201-sai-dual.symboltest.net:3001/account/balance" \
  -H 'Content-Type: application/json'  -H 'Accept: application/json'\
  -d '{
  "network_identifier": {
    "blockchain": "Symbol",
    "network": "testnet"
  },
  "account_identifier": {
    "address": "TCSQ4QFFX75JKC4K4X73WP5KFDHBRE3LRCMJSAQ"
  }
}' | jq
{
  "block_identifier": {
    "index": 3001142,
    "hash": "66DF291BB6A38774498ACD868F9DA8019E9E2E4423BBCA826F3F7C24C12A9375"
  },
  "balances": [
    {
      "value": "100000",
      "currency": {
        "symbol": "symbol.xym",
        "decimals": 6,
        "metadata": {
          "id": "72C0212E67A08BCE"
        }
      }
    }
  ]
}

Step 10: Get Block information

Get details about a specific block by using its block number.

Endpoint

  • Path: /block
  • Method: POST
  • Required Parameters:
    • BlockIdentifier

Check the transaction in block 3000412. You’ll see there are more operations than just the transfer, including operations for the harvest fee receipts in that block.

curl -s -X POST https://201-sai-dual.symboltest.net:3001/block \ 
  -H 'Content-Type: application/json' \
  -d '{
  "network_identifier": {
    "blockchain": "Symbol",
    "network": "testnet"
  },
  "block_identifier": {
    "index": 3000412
  }
}' | jq
{
  "block": {
    "block_identifier": {
      "index": 3000412,
      "hash": "088C7CF71EE6BEA1A14848A339294A74E6A3EA2E29FC80DCC5F77CCFDA5D43B6"
    },
    "parent_block_identifier": {
      "index": 3000411,
      "hash": "EA7487334032BC695B9062E6B647D581112FBD8EB80C3385A13D0FFB1C3A3367"
    },
    "timestamp": 1767053263184,
    "transactions": [
      {
        "transaction_identifier": {
          "hash": "5D32C48A49292D8918EB08C2595608E747C2090F5764B49C13216E14D7F32E34"
        },
        "operations": [
          {
            "operation_identifier": {
              "index": 0
            },
            "type": "transfer",
            "status": "success",
            "account": {
              "address": "TCGK56TPAMEIB2EGRJGNJ66INLGVPJ7EO436LEQ"
            },
            "amount": {
              "value": "-100000",
              "currency": {
                "symbol": "symbol.xym",
                "decimals": 6,
                "metadata": {
                  "id": "72C0212E67A08BCE"
                }
              }
            }
          },
          {
            "operation_identifier": {
              "index": 1
            },
            "type": "transfer",
            "status": "success",
            "account": {
              "address": "TCSQ4QFFX75JKC4K4X73WP5KFDHBRE3LRCMJSAQ"
            },
            "amount": {
              "value": "100000",
              "currency": {
                "symbol": "symbol.xym",
                "decimals": 6,
                "metadata": {
                  "id": "72C0212E67A08BCE"
                }
              }
            }
          },
          {
            "operation_identifier": {
              "index": 2
            },
            "type": "transfer",
            "status": "success",
            "account": {
              "address": "TCGK56TPAMEIB2EGRJGNJ66INLGVPJ7EO436LEQ"
            },
            "amount": {
              "value": "-26400",
              "currency": {
                "symbol": "symbol.xym",
                "decimals": 6,
                "metadata": {
                  "id": "72C0212E67A08BCE"
                }
              }
            }
          }
        ]
      },
      {
        "transaction_identifier": {
          "hash": "088C7CF71EE6BEA1A14848A339294A74E6A3EA2E29FC80DCC5F77CCFDA5D43B6"
        },
        "operations": [
          {
            "operation_identifier": {
              "index": 0
            },
            "type": "transfer",
            "status": "success",
            "account": {
              "address": "TBYPASOMI2FS4Z3VV6W4WPEI6I54A3GERLNEMIA"
            },
            "amount": {
              "value": "112655730",
              "currency": {
                "symbol": "symbol.xym",
                "decimals": 6,
                "metadata": {
                  "id": "72C0212E67A08BCE"
                }
              }
            }
          },
          {
            "operation_identifier": {
              "index": 1
            },
            "type": "transfer",
            "status": "success",
            "account": {
              "address": "TBC3AX4TMSYWTCWR6LDHPKWQQL7KPCOMHECN2II"
            },
            "amount": {
              "value": "5929248",
              "currency": {
                "symbol": "symbol.xym",
                "decimals": 6,
                "metadata": {
                  "id": "72C0212E67A08BCE"
                }
              }
            }
          }
        ]
      }
    ]
  }
}

Conclusion

By following these steps, you can generate, sign, and send a transfer transaction to the blockchain using Coinbase’s Mesh API. Since the example uses HTTP, you can use any programming language that can sign the transaction.

Always keep your private keys safe, and make sure to test your transactions on a testnet before using the mainnet.

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?