Skip to content

Commit

Permalink
Merge pull request #6 from Emurgo/feature/add-transaction-builder
Browse files Browse the repository at this point in the history
Feature/add transaction builder
  • Loading branch information
v-almonacid committed Jul 28, 2020
2 parents 14db56b + f357d91 commit 967cef4
Show file tree
Hide file tree
Showing 33 changed files with 1,639 additions and 80 deletions.
14 changes: 3 additions & 11 deletions README.md
Expand Up @@ -11,19 +11,11 @@
`$ react-native link react-native-haskell-shelley`

## Usage
```javascript
import HaskellShelley from 'react-native-haskell-shelley';

// TODO: What to do with the module?
HaskellShelley;
```
See examples in [`App.js`](example/App.js).

## How to add new classes and functions

(WIP)

Note: the terms function and method may be used interchangeably.

The process is basically as follows: we start by writting a rust wrapper of some struct method from our target rust library. Both iOS and Android require specific rust wrappers, so there are separate folder (`rust/ios` and `rust/android`). When this project is compiled by the host react native app, all the wrappers are transformed into a native library. In Android, java can directly interact with the rust binaries (the instructions for compiling our rust library are in `build.gradle`), while in iOS there is an additional step in which the rust library is transformed into C, with which can we easily interact with through Objective-C. This intermediate step is contained in `ios/build.sh`, where we basically use `cbindgen` to automatically generate C binaries as well as C headers (which are written in `rust/include/react_native_haskell_shelley.h`).
After writing the corresponding iOS and Android wrappers, we finally just write a simple JS library in `index.js` and define its types in `index.d.ts`.

Expand Down Expand Up @@ -55,12 +47,12 @@ As you may have noticed, the two steps above are equivalent to those with Androi

For every new function in the module:
- Add a rust wrapper of the form: `pub unsafe extern "C" fn function_name_in_snake_case`
- Write a iOS-native wrapper in Objective-C in `ios/HaskellShelley.m`. In contrast to Android (java), the iOS native wrappers can't directly interact with rust so we actually use a C library.
- Write a iOS-native wrapper in Objective-C in `ios/HaskellShelley.m`. In contrast to Android (java), the iOS native wrappers can't directly interact with rust so we actually use a C library. This C library is automatically generated by `cargo` when the project is built.


### Additional steps in Rust

- Add new classes in `rust/src/ptr_impl.rs`
- Any new struct from `cardano_serialization_lib` that is required either as an input or output in our rust wrappers must implement the `RPtrRepresentable` trait. Add them in [`ptr_impl.rs`](rust/src/ptr_impl.rs).

### Javascript

Expand Down
Expand Up @@ -227,6 +227,22 @@ public final void stakeCredentialKind(String stakeCredential, Promise promise) {
.pour(promise);
}

@ReactMethod
public final void stakeCredentialToBytes(String stakeCredential, Promise promise) {
Native.I
.stakeCredentialToBytes(new RPtr(stakeCredential))
.map(bytes -> Base64.encodeToString(bytes, Base64.DEFAULT))
.pour(promise);
}

@ReactMethod
public final void stakeCredentialFromBytes(String bytes, Promise promise) {
Native.I
.stakeCredentialFromBytes(Base64.decode(bytes, Base64.DEFAULT))
.map(RPtr::toJs)
.pour(promise);
}

// BaseAddress

@ReactMethod
Expand Down Expand Up @@ -447,4 +463,140 @@ public final void transactionWitnessSetSetBootstraps(String witnessSet, String b
.pour(promise);
}

// TransactionBody

@ReactMethod
public final void transactionBodyToBytes(String transactionBody, Promise promise) {
Native.I
.transactionBodyToBytes(new RPtr(transactionBody))
.map(bytes -> Base64.encodeToString(bytes, Base64.DEFAULT))
.pour(promise);
}

@ReactMethod
public final void transactionBodyFromBytes(String bytes, Promise promise) {
Native.I
.transactionBodyFromBytes(Base64.decode(bytes, Base64.DEFAULT))
.map(RPtr::toJs)
.pour(promise);
}

// Transaction

@ReactMethod
public final void transactionNew(String body, String witnessSet, Promise promise) {
Native.I
.transactionNew(new RPtr(body), new RPtr(witnessSet))
.map(RPtr::toJs)
.pour(promise);
}

@ReactMethod
public final void transactionToBytes(String transaction, Promise promise) {
Native.I
.transactionToBytes(new RPtr(transaction))
.map(bytes -> Base64.encodeToString(bytes, Base64.DEFAULT))
.pour(promise);
}

@ReactMethod
public final void transactionFromBytes(String bytes, Promise promise) {
Native.I
.transactionFromBytes(Base64.decode(bytes, Base64.DEFAULT))
.map(RPtr::toJs)
.pour(promise);
}

// TransactionBuilder

@ReactMethod
public final void transactionBuilderAddKeyInput(String txBuilder, String hash, String input, String amount, Promise promise) {
Native.I
.transactionBuilderAddKeyInput(new RPtr(txBuilder), new RPtr(hash), new RPtr(input), new RPtr(amount))
.pour(promise);
}

@ReactMethod
public final void transactionBuilderAddBootstrapInput(String txBuilder, String hash, String input, String amount, Promise promise) {
Native.I
.transactionBuilderAddBootstrapInput(new RPtr(txBuilder), new RPtr(hash), new RPtr(input), new RPtr(amount))
.pour(promise);
}

@ReactMethod
public final void transactionBuilderAddOutput(String txBuilder, String output, Promise promise) {
Native.I
.transactionBuilderAddOutput(new RPtr(txBuilder), new RPtr(output))
.pour(promise);
}

@ReactMethod
public final void transactionBuilderSetFee(String txBuilder, String fee, Promise promise) {
Native.I
.transactionBuilderSetFee(new RPtr(txBuilder), new RPtr(fee))
.pour(promise);
}

@ReactMethod
public final void transactionBuilderSetTtl(String txBuilder, Double ttl, Promise promise) {
Native.I
.transactionBuilderSetTtl(new RPtr(txBuilder), ttl.longValue())
.pour(promise);
}

@ReactMethod
public final void transactionBuilderNew(String linearFee, String minimumUtxoVal, String poolDeposit, String keyDeposit, Promise promise) {
Native.I
.transactionBuilderNew(new RPtr(linearFee), new RPtr(minimumUtxoVal), new RPtr(poolDeposit), new RPtr(keyDeposit))
.map(RPtr::toJs)
.pour(promise);
}

@ReactMethod
public final void transactionBuilderGetExplicitInput(String txBuilder, Promise promise) {
Native.I
.transactionBuilderGetExplicitInput(new RPtr(txBuilder))
.map(RPtr::toJs)
.pour(promise);
}

@ReactMethod
public final void transactionBuilderGetImplicitInput(String txBuilder, Promise promise) {
Native.I
.transactionBuilderGetImplicitInput(new RPtr(txBuilder))
.map(RPtr::toJs)
.pour(promise);
}

@ReactMethod
public final void transactionBuilderGetExplicitOutput(String txBuilder, Promise promise) {
Native.I
.transactionBuilderGetExplicitOutput(new RPtr(txBuilder))
.map(RPtr::toJs)
.pour(promise);
}

@ReactMethod
public final void transactionBuilderAddChangeIfNeeded(String txBuilder, String address, Promise promise) {
Native.I
.transactionBuilderAddChangeIfNeeded(new RPtr(txBuilder), new RPtr(address))
.pour(promise);
}

@ReactMethod
public final void transactionBuilderBuild(String txBuilder, Promise promise) {
Native.I
.transactionBuilderBuild(new RPtr(txBuilder))
.map(RPtr::toJs)
.pour(promise);
}

@ReactMethod
public final void transactionBuilderEstimateFee(String txBuilder, Promise promise) {
Native.I
.transactionBuilderEstimateFee(new RPtr(txBuilder))
.map(RPtr::toJs)
.pour(promise);
}

}
25 changes: 25 additions & 0 deletions android/src/main/java/io/emurgo/rnhaskellshelley/Native.java
Expand Up @@ -55,6 +55,8 @@ private Native() { }
public final native Result<RPtr> stakeCredentialFromKeyHash(RPtr keyHash);
public final native Result<RPtr> stakeCredentialToKeyHash(RPtr stakeCredential);
public final native Result<Integer> stakeCredentialKind(RPtr stakeCredential);
public final native Result<byte[]> stakeCredentialToBytes(RPtr stakeCredential);
public final native Result<RPtr> stakeCredentialFromBytes(byte[] bytes);

// BaseAddress
public final native Result<RPtr> baseAddressNew(int network, RPtr payment, RPtr stake);
Expand Down Expand Up @@ -98,5 +100,28 @@ private Native() { }
public final native Result<Void> transactionWitnessSetSetVkeys(RPtr witnessSet, RPtr vkeys);
public final native Result<Void> transactionWitnessSetSetBootstraps(RPtr witnessSet, RPtr bootstraps);

// TransactionBody
public final native Result<byte[]> transactionBodyToBytes(RPtr TransactionBody);
public final native Result<RPtr> transactionBodyFromBytes(byte[] bytes);

// Transaction
public final native Result<RPtr> transactionNew(RPtr body, RPtr witnessSet);
public final native Result<byte[]> transactionToBytes(RPtr Transaction);
public final native Result<RPtr> transactionFromBytes(byte[] bytes);

// TransactionBuilder
public final native Result<Void> transactionBuilderAddKeyInput(RPtr txBuilder, RPtr hash, RPtr input, RPtr value);
public final native Result<Void> transactionBuilderAddBootstrapInput(RPtr txBuilder, RPtr hash, RPtr input, RPtr value);
public final native Result<Void> transactionBuilderAddOutput(RPtr txBuilder, RPtr input);
public final native Result<Void> transactionBuilderSetFee(RPtr txBuilder, RPtr fee);
public final native Result<Void> transactionBuilderSetTtl(RPtr txBuilder, long ttl);
public final native Result<RPtr> transactionBuilderNew(RPtr linearFee, RPtr minimumUtxoVal, RPtr poolDeposit, RPtr keyDeposit);
public final native Result<RPtr> transactionBuilderGetExplicitInput(RPtr txBuilder);
public final native Result<RPtr> transactionBuilderGetImplicitInput(RPtr txBuilder);
public final native Result<RPtr> transactionBuilderGetExplicitOutput(RPtr txBuilder);
public final native Result<Boolean> transactionBuilderAddChangeIfNeeded(RPtr txBuilder, RPtr address);
public final native Result<RPtr> transactionBuilderBuild(RPtr txBuilder);
public final native Result<RPtr> transactionBuilderEstimateFee(RPtr txBuilder);

public final native void ptrFree(RPtr ptr);
}

0 comments on commit 967cef4

Please sign in to comment.