Skip to content

Commit

Permalink
Merge pull request input-output-hk#50 from input-output-hk/add-doc-tr…
Browse files Browse the repository at this point in the history
…ansaction-builder

Add doc for transaction builder
  • Loading branch information
NicolasDP authored Feb 18, 2019
2 parents f2cc580 + 4e12180 commit 104634c
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 4 deletions.
2 changes: 1 addition & 1 deletion cardano-wallet/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cardano-wallet"
version = "0.2.3"
version = "0.2.4"
authors = ["Nicolas Di Prima <[email protected]>"]
description = "Cardano Wallet, from rust to JS via Wasm"
homepage = "https://github.com/input-output-hk/js-cardano-wasm#README.md"
Expand Down
84 changes: 84 additions & 0 deletions cardano-wallet/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ Now remember, with great power comes great responsibility. You can now
write a cardano wallet, redeem your certificates, create and sign
transactions.

## Example on how to retrieve a wallet from mnemonics

The example below shows you how to create/retrieve a wallet from
the mnemonics and the password.

```js
import * as Cardano from "cardano-wallet";

Expand All @@ -44,3 +49,82 @@ let address = key_pub.bootstrap_era_address(settings);

console.log("Address m/bip44/ada/'0/0/0", address.to_base58());
```

## Create a transaction:

The example below shows how to create a transaction, this transaction is not
ready to be sent through the network. It shows that there is separation of
concerns between the transaction you build/prepare and signing the transaction
in the last example.

```js
// assuming the xprv and the settings from the example above are available in this scope

const inputs = [
{ pointer: { id: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", index: 1 }, value: 1 },
{ pointer: { id: "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210", index: 0 }, value: 1 }
];
const outputs = [
{ address: "Ae2tdPwUPEZCEhYAUVU7evPfQCJjyuwM6n81x6hSjU9TBMSy2YwZEVydssL", value: "1826205" }
];

// the fee algorithm (i.e. the function to compute the fees of a transaction)
const fee_algorithm = Wallet.LinearFeeAlgorithm.default();

let transaction_builder = new Wallet.TransactionBuilder();

for (let index = 0; index < inputs.length; index++) {
const pointer = Wallet.TxoPointer.from_json(inputs[index].pointer);
const value = Wallet.Coin.from(inputs[index].value, 0);
transaction_builder.add_input(pointer, value);
}

for (let index = 0; index < outputs.length; index++) {
const txout = Wallet.TxOut.from_json(outputs[index]);
transaction_builder.add_output(txout);
}

// verify the balance and the fees:
const balance = transaction_builder.get_balance(fee_algorithm);
if (balance.is_negative()) {
console.error("not enough inputs, ", balance.value().to_str());
throw Error("Not enough inputs");
} else {
if (balance.is_zero()) {
console.info("Perfect balance no dust");
} else {
console.warn("Loosing some coins in extra fees: ", balance.value().to_str());
}
}

// Warning: this function does not throw exception if the transaction is not
// balanced. This is your job to make sure your transaction's inputs and outputs
// and fees are balanced.
let transaction = transaction_builder.make_transaction();
```

## Signing a transaction

This function shows how to sign a transaction so it can be accepted by the
network.

You need to make sure:

1. the key_prv correspond to the private key associated to the address for the given
input (see UTxO based crypto-currency model/documentations);
2. the signatures are added in the same order the inputs of this transaction
were added.

```js
// retrieve the prepared transaction from the previous example
let transaction_finalizer = new Wallet.TransactionFinalized(transaction);

for (let index = 0; index < inputs.length; index++) {
transaction_finalizer.sign(settings, key_prv);
}

// at this stage the transaction is ready to be sent
const signed_transaction = transaction_finalizer.finalize();
console.log("ready to send transaction: ", signed_transaction.to_hex());
console.log(signed_transaction.to_json());
```
3 changes: 2 additions & 1 deletion cardano-wallet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -724,7 +724,7 @@ impl TxOut {
}

/// retrieve the object from a JsValue.
pub fn from_json(value: JsValue) -> Result<TxoPointer, JsValue> {
pub fn from_json(value: JsValue) -> Result<TxOut, JsValue> {
value
.into_serde()
.map_err(|e| JsValue::from_str(&format! {"{:?}", e}))
Expand Down Expand Up @@ -912,6 +912,7 @@ pub struct TransactionFinalized {
}
#[wasm_bindgen]
impl TransactionFinalized {
#[wasm_bindgen(constructor)]
pub fn new(transaction: Transaction) -> TransactionFinalized {
TransactionFinalized {
tx_id: transaction.0.id(),
Expand Down
64 changes: 62 additions & 2 deletions cardano-wallet/tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ let RustWallet = null;

Wallet
.then(Wallet => {
console.log("loaded...");

const MNEMONICS = "crowd captain hungry tray powder motor coast oppose month shed parent mystery torch resemble index";
const PASSWORD = "Cardano Rust for the winners!";

Expand All @@ -26,5 +24,67 @@ Wallet
let address = key_pub.bootstrap_era_address(settings);

console.log("Address m/bip44/ada/'0/0/0", address.to_base58());

// Building a transaction

let transaction_builder = new Wallet.TransactionBuilder();

const inputs = [
{ pointer: { id: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", index: 1 }, value: 1 },
{ pointer: { id: "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210", index: 0 }, value: 1 }
];
const outputs = [
// TODO: you can test the balance by changing the value here.
{ address: "Ae2tdPwUPEZCEhYAUVU7evPfQCJjyuwM6n81x6hSjU9TBMSy2YwZEVydssL", value: "1826205" }
];

for (let index = 0; index < inputs.length; index++) {
const pointer = Wallet.TxoPointer.from_json(inputs[index].pointer);
const value = Wallet.Coin.from(inputs[index].value, 0);
transaction_builder.add_input(pointer, value);
}

console.log("all inputs set...", transaction_builder.get_input_total().to_str());

for (let index = 0; index < outputs.length; index++) {
const txout = Wallet.TxOut.from_json(outputs[index]);
transaction_builder.add_output(txout);
}

console.log("all outputs set...", transaction_builder.get_output_total().to_str());

// verify the balance and the fees:
const fee_algorithm = Wallet.LinearFeeAlgorithm.default();
const balance = transaction_builder.get_balance(fee_algorithm);
if (balance.is_negative()) {
console.error("not enough inputs, ", balance.value().to_str());
throw Error("Not enough inputs");
} else {
if (balance.is_zero()) {
console.info("Perfect balance no dust");
} else {
console.warn("Loosing some coins in extra fees: ", balance.value().to_str());
}
}

let transaction = transaction_builder.make_transaction();

console.log("unsigned transaction built");

let transaction_finalizer = new Wallet.TransactionFinalized(transaction);

console.log("transaction finalizer built", transaction_finalizer);

for (let index = 0; index < inputs.length; index++) {
transaction_finalizer.sign(settings, key_prv);
console.log("signature ", index, "added");

}

// at this stage the transaction is ready to be sent
const signed_transaction = transaction_finalizer.finalize();
console.log("ready to send transaction: ", signed_transaction.to_hex());
console.log(signed_transaction.to_json());

})
.catch(console.error);

0 comments on commit 104634c

Please sign in to comment.