-
Notifications
You must be signed in to change notification settings - Fork 8
Resources
A flutter wallet library based on trust wallet core. This document will serve as log to capture all research, findings and decisions made in the library.
- Based on this https://github.com/trustwallet/wallet-core , we want to develop a dart library that can interact with the trust wallet core library. https://github.com/EjaraApp/trustdart .
- A similar project had already been started here but was never completed. π https://github.com/trustwallet/wallet-core/issues/1200
- Basically the way to go is to write a dart wrapper around the ios and android libraries of the trust wallet core using platform channels.
- Good examples of such a plugins can be found here π https://github.com/j0j00/flutter_liquidcore, https://github.com/HomeXLabs/pusher-websocket-flutter. They use platform channels just as we intend to use so there might be some good examples for us there.
- Here is the dart doc that is concerned with dart package development πhttps://flutter.dev/docs/development/packages-and-plugins/developing-packages
- This site also provided good advice for developing plugins https://medium.com/flutter/writing-a-good-flutter-plugin-1a561b986c9c.
- This doc π https://dart.dev/guides/libraries/create-library-packages gives standard recommendations for organizing library code.
- This doc elaborates on platform channels π https://flutter.dev/docs/development/platform-integration/platform-channels. And a good example project https://github.com/alex-melnyk/flutter_ext_plugin.
- Proper documentation practices π https://dart.dev/guides/language/effective-dart/documentation .
- https://codelabs.developers.google.com/codelabs/write-flutter-plugin
- https://medium.com/litslink/flutter-the-way-to-make-a-plugin-277204660906
- https://medium.com/flutter-community/creating-a-flutter-plugin-dialog-box-78adbff15fe
- https://proandroiddev.com/build-your-own-plugin-for-flutter-cfee1a08ea3a
- https://rudderstack.com/blog/developing-a-custom-plugin-using-flutter
- https://flutterdevs.com/blog/creating-a-flutter-plugin-for-android-and-ios-image-gallery/
- https://github.com/HomeXLabs/pusher-websocket-flutter
- In dart this project is a
plugin
. See the difference here π https://flutter.dev/docs/development/packages-and-plugins/using-packages. - A git repository was already created for the project.
- Hence to initialize it, the following command was used.
flutter create --org africa.ejara --template=plugin --platforms=android,ios --android-language kotlin --ios-language swift --project-name trustdart .
- Since trust wallet core has native ios and android dependencies, that needs to be added to the build.gradle and podspec files of android and ios folders.
- Refere to the trust wallet integration guide π https://developer.trustwallet.com/wallet-core/integration-guide for the library names.
- This section π https://flutter.dev/docs/development/packages-and-plugins/developing-packages#dependencies of the flutter site describes where exactly to include the library names.
- For more information on build.gradle files, see π https://docs.gradle.org/current/userguide/tutorial_using_tasks.html.
- For additional details on .podspec files, see π https://guides.cocoapods.org/syntax/podspec.html.
- https://github.com/trustwallet/wallet-core/tree/master/include/TrustWalletCore
- https://github.com/trustwallet/wallet-core/tree/master/tests/interface
- https://github.com/trustwallet/wallet-core/tree/master/swift/Tests
- https://github.com/trustwallet/wallet-core/tree/master/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains
The plugin uses;
- kotlin for android π https://kotlinlang.org/ .
- swift for ios π https://swift.org/ .
Here we describe the api of the trustdart wallet library. Basically any crypto has the following functionalities;
- Wallet management
- Creating a new multi-coin wallet
- Importing a multi-coin wallet
- Address derivation (receiving)
- Generating the default address for a coin
- Generating an address using a custom derivation path (expert)
- Transaction building (e.g. for sending)
Hence from these the following methods would be exposed
createWallet
importWalletFromMnemonic
generateAddressForCoin
validateAddressForCoin
buildAndSignTransaction
The trustwallet library seems to have a cointype object that when imported one can access all coins. For example here is how its imported in kotlin android https://github.com/trustwallet/wallet-core/blob/4a4eb20f7f6f21ea92cec5736dc46544ba2a6685/samples/android/app/src/main/java/com/trust/walletcore/example/MainActivity.kt#L8 , and here is an example usage https://github.com/trustwallet/wallet-core/blob/4a4eb20f7f6f21ea92cec5736dc46544ba2a6685/samples/android/app/src/main/java/com/trust/walletcore/example/MainActivity.kt#L62 .
This file here https://github.com/trustwallet/wallet-core/blob/master/src/Coin.cpp contains methods one can call directly on the cointype, for example deriveAddress
https://github.com/trustwallet/wallet-core/blob/4a4eb20f7f6f21ea92cec5736dc46544ba2a6685/src/Coin.cpp#L208 . For example CoinType.BITCOIN.deriveAddress
.
Sometime it the above rule does not apply. For example with validateAddress
https://github.com/trustwallet/wallet-core/blob/4a4eb20f7f6f21ea92cec5736dc46544ba2a6685/src/Coin.cpp#L208 would be invoked in kotlin as CoinType.BITCOIN.validate
. Basically just try the first word or the sensible ones.
Since there is no formal documentation, one has to resort to means like reflection to determine all the members of a class.
Just add the following dependency to your build.gradle file
dependencies {
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
}
Now you can use reflection during development just to figure out members of an object. Here is an example to figure out members of PrivateKey
class.
val privateKey = wallet.getKey(CoinType.TEZOS, path)
val opJson = JSONObject(txData).toString();
println(privateKey::class.members)
for (prop in privateKey::class.members) {
println("${prop.name}")
}
Here is the output
I/System.out(13648): [fun wallet.core.jni.PrivateKey.sign(kotlin.ByteArray!, wallet.core.jni.Curve!): kotlin.ByteArray!, fun wallet.core.jni.PrivateKey.getPublicKeySecp256k1(kotlin.Boolean): wallet.core.jni.PublicKey!, fun wallet.core.jni.PrivateKey.signAsDER(kotlin.ByteArray!, wallet.core.jni.Curve!): kotlin.ByteArray!, fun wallet.core.jni.PrivateKey.getPublicKeyEd25519Extended(): wallet.core.jni.PublicKey!, fun wallet.core.jni.PrivateKey.getPublicKeyEd25519Blake2b(): wallet.core.jni.PublicKey!, fun wallet.core.jni.PrivateKey.getPublicKeyCurve25519(): wallet.core.jni.PublicKey!, fun wallet.core.jni.PrivateKey.signSchnorr(kotlin.ByteArray!, wallet.core.jni.Curve!): kotlin.ByteArray!, fun wallet.core.jni.PrivateKey.getPublicKeyNist256p1(): wallet.core.jni.PublicKey!, fun wallet.core.jni.PrivateKey.data(): kotlin.ByteArray!, fun wallet.core.jni.PrivateKey.getPublicKeyEd25519(): wallet.core.jni.PublicKey!, fun wallet.core.jni.PrivateKey.getSharedKey(wallet.core.jni.PublicKey!, wallet.core.jni.Curve!): kotlin.ByteArray!, var wallet.core.jni.PrivateKey.nativeHandle: kotlin.Long, fun wallet.core.jni.PrivateKey.hashCode(): kotlin.Int, fun wallet.core.jni.PrivateKey.equals(kotlin.Any?): kotlin.Boolean, fun wallet.core.jni.PrivateKey.toString(): kotlin.String, fun createFromNative(kotlin.Long): wallet.core.jni.PrivateKey!, fun isValid(kotlin.ByteArray!, wallet.core.jni.Curve!): kotlin.Boolean, fun nativeCreate(): kotlin.Long, fun nativeCreateCopy(wallet.core.jni.PrivateKey!): kotlin.Long, fun nativeCreateWithData(kotlin.ByteArray!): kotlin.Long, fun nativeDelete(kotlin.Long): kotlin.Unit]
I/System.out(13648): sign
I/System.out(13648): getPublicKeySecp256k1
I/System.out(13648): signAsDER
I/System.out(13648): getPublicKeyEd25519Extended
I/System.out(13648): getPublicKeyEd25519Blake2b
I/System.out(13648): getPublicKeyCurve25519
I/System.out(13648): signSchnorr
I/System.out(13648): getPublicKeyNist256p1
I/System.out(13648): data
I/System.out(13648): getPublicKeyEd25519
I/System.out(13648): getSharedKey
I/System.out(13648): nativeHandle
I/System.out(13648): hashCode
I/System.out(13648): equals
I/System.out(13648): toString
I/System.out(13648): createFromNative
I/System.out(13648): isValid
I/System.out(13648): nativeCreate
I/System.out(13648): nativeCreateCopy
I/System.out(13648): nativeCreateWithData
I/System.out(13648): nativeDelete
For IoS (using xcode) there was no need for this since method completion was working perfectly as well as links to methods. For Android (android studio) method completion wasn't working for some unknown reason.
- For android these set of tests provide a good pointer for building transactions
- For ios
https://github.com/trustwallet/wallet-core/tree/master/swift/Tests/Blockchains
-
Example signing android https://github.com/trustwallet/wallet-core/blob/master/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/tezos/TestTezosSigner.kt ios
-
Tezos message types https://github.com/Cryptonomic/ConseilJS/blob/master/src/types/tezos/TezosP2PMessageTypes.ts
-
Understanding Tezos Operations https://opentezos.com/tezos-basics/operations