SDK Development

A key objective is that interoperability becomes a natural design of the NEM2-SDK. Follow this guideline to collaborate creating a NEM SDK, achieving the best quality with the less effort.

Learning about Catapult

In case you haven’t used NEM2-SDK or Catapult in general, we encourage you to:

  1. Review the technical documentation to become familiar with the NEM built-in features.
  2. Setup the catapult in local environment via docker or enroll the beta program to access a Catapult Test Net without the need to run it yourself.
  3. Check the API reference and play with the API endpoints.
  4. Become familiar with the current nem2-sdk via code examples & nem2-cli .
  5. Join our Slack to ask Catapult related questions.

Development

You can base your work in TypeScript and Java SDKs. The TypeScript version is the first SDK getting the latest updates. Meanwhile, Java takes longer to be updated.

Unfortunately, TypeScript version has one specific implementation detail: the low level implementation is separated from the SDK, called nem2-library-js. There was a need to create this low-level library to perform specific chain testing.

The SDKs you create does not require this separate implementation.

Regularly check the Changelog to be sure you didn’t miss any code change update.

Before starting

  1. Be sure no one is already working on the SDK you want to create. Check the repository list, if someone is already working on it, we suggest you collaborate with him/her.
  2. Claim the SDK forking this repository and adding a new entry to the repository list.
  3. Consider using one of the suggested licenses.

Creating the project

  1. Add a README with the instructions to install the SDK. Find here a template.
  2. Add a Code of Conduct. Find here an example.
  3. Add a Contributors guidelines to help others know how they can help you. Find here a CONTRIBUTING.md template.
  4. Setup the Continuous Integration system. We use travis-ci, but feel free to use the one suits you best.

A project with a good test coverage it’s more likely to be used and trusted by the developers!

We strongly suggest you to do Test-Driven Development or Unit-Testing (test last). If you need inspiration, you can adapt the same tests we did.

API Wrapper

The API generation can be done with Swagger Codegen. It supports multiple languages. Hopefully, yours in the list.

The API swagger file definition can be found here.

Java example. The code generated by swagger are the DTOs.

We drop the client classes and instead we implement them using the Repository pattern returning Observables of ReactiveX.

List of interfaces:

Check the Http implementations in case you doubt about some API endpoint.

Warning

The repositories return Models instead of DTOs. You will need to code the Models before finish the API wrapper.

Models

Java models example.

The models are by default immutable. The models aim to hide the complexity, like type conversion or relationship between objects.

You will find in the different implementations different invariants to ensure the object is well constructed and a nicer API is published.

Particular decisions to consider:

  • uint64 support: meanwhile Java supports big numbers, for example JavaScript doesn’t. The JavaScript SDK has a custom class to handle the uint64 types. If your language supports uint64 use that implementation. Otherwise, adapt the UInt64.ts implementation to your language.
  • API conversions: The API returns the data sometimes compressed, you might need to convert that types for the user.
  • Mosaics & Namespaces IDs: The namespaces and mosaics aren’t strings any more compared to NIS1. As you can see in the class, the string name is optional. At creation time you add the string name, but when you receive the Namespace/Mosaic from the network, it comes in formatted asuint64 ID. A specific endpoint returns the Namespace/Mosaic string name. We did a Service to return the Mosaic with the string name automatically for the user, check the implementation here (only available in TypeScript SDK version).

Transaction Serialization

Warning

The Transaction Serialization will change when catbuffer tool is finished. Meanwhile, we will use flatbuffers.

A Transaction needs a particular serialization schema in binary optimized in size. The transaction serialization has multiple steps to keep easy to create transactions and maintain the schema serialization.

Generating the buffer classes: The easy part

  1. Install the flatbuffers tool, you might need to compile it. Use version 1.7.1 or newer.
  2. Compile the schema for your language. Download the flatbuffers files here.
  3. Move the generated files to your model/transaction SDK folder. Example.

Creating the Schema class: The difficult part

  1. Create the Schema class.
  2. Create the SchemaAttribute class.
  3. Create the ScalarAttribute class.
  4. Create the ArrayAttribute class.
  5. Create the TableAttribute class.
  6. Create the TableArrayAttribute class.
  7. Constants class.

Creating the Transaction Schemas

Each transaction has a Schema. It has the same type as flatbuffer schemas but using the Schema class. It’s used to know where each component is located in the flatbuffer schema and remove the unnecessary bytes to create the optimized serialization.

  1. AggregateTransactionSchema.
  2. LockFundsTransactionSchema.
  3. ModifyMultisigAccountTransactionSchema.
  4. MosaicDefinitionTransactionSchema.
  5. MosaicSupplyChangeTransactionSchema.
  6. RegisterNamespaceTransactionSchema.
  7. SecretLockTransactionSchema.
  8. SecretProofTransactionSchema.
  9. TransferTransactionSchema.

Using the Schemas in the Transaction Models

The Transaction class has the abstract method generateBytes(). Each Transaction has to implement and use the previous classes, the Buffers and the Schemas, to serialize the transaction.

  1. AggregateTransaction.generateBytes().
  2. LockFundsTransaction.generateBytes().
  3. ModifyMultisigAccountTransaction.generateBytes().
  4. MosaicDefinitionTransaction.generateBytes().
  5. MosaicSupplyChangeTransaction.generateBytes().
  6. RegisterNamespaceTransaction.generateBytes().
  7. SecretLockTransaction.generateBytes().
  8. SecretProofTransaction.generateBytes().
  9. TransferTransaction.generateBytes().

Do not forget about Cosignatory classes, it has to be done too.

KeyPair and Cryptographic functions

Warning

This section is incomplete.

Documenting your SDK

SDKs need to be adopted by other developers. As a contributor, no one knows better than you how a determined SDK works. Consider helping others and spread the usage of the SDK by providing the following documentation.

Publishing the SDK as official

When you open-source your code, submit the repository to this page.

To become an accepted SDK, it should be proposed as a NIP. The reason behind the NEM2 Improvement Proposal is to ensure that the new libraries are reviewed, tested and shared among NEM developers.

Future work

The current guideline shows what is done up to today since the SDK isn’t complete. It will get updates according to the latest architecture/features.