Skip to content

Commit

Permalink
Merge pull request #131 from kommitters/v0.5
Browse files Browse the repository at this point in the history
Release for v0.5
  • Loading branch information
Juan Hurtado authored Mar 22, 2022
2 parents 6c1c690 + 5d74aab commit 9e92c3d
Show file tree
Hide file tree
Showing 16 changed files with 370 additions and 24 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 0.5.0 (21.03.2022)
* Enable signatures for base64-encoded transaction envelopes.
* Improve library docs.

## 0.4.0 (11.03.2022)
* Compose functional Horizon requests.
* Build structures for Horizon resources.
Expand Down
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,23 @@
![Downloads Badge](https://img.shields.io/hexpm/dt/stellar_sdk?style=for-the-badge)
[![License badge](https://img.shields.io/hexpm/l/stellar_sdk.svg?style=for-the-badge)](https://github.com/kommitters/stellar_sdk/blob/main/LICENSE.md)

**`stellar_sdk`** is an **Elixir library** that provides a client for interfacing with **Horizon** endpoints to retrieve ledger information, and to submit transactions. **`stelar_sdk`** uses the [**`stellar_base`**][base] library to enable the construction, signing and encoding of Stellar primitive XDR constructs.
The **Stellar SDK** enables the construction, signing and encoding of Stellar [transactions][stellar-docs-tx] and [operations][stellar-docs-list-operations] in **Elixir**, as well as provides a client for interfacing with [Horizon][horizon-api] server REST endpoints to retrieve ledger information, and to submit transactions.

This library is aimed at developers building Elixir applications that interact with the [**Stellar network**][stellar].

## Documentation
* [**Building transactions**](#building-transactions)
* [**Querying Horizon**](#querying-horizon)
* [**Examples**](/docs/examples.md)
The **Stellar SDK** is composed of two complementary components: **`TxBuild`** + **`Horizon`**.
* **`TxBuild`** - used for [**building transactions.**](#building-transactions)
* **`Horizon`** - used for [**querying Horizon.**](#querying-horizon)
* [**Examples.**](/docs/examples.md)

## Installation
[**Available in Hex**][hex], add `stellar_sdk` to your list of dependencies in `mix.exs`:

```elixir
def deps do
[
{:stellar_sdk, "~> 0.4.0"}
{:stellar_sdk, "~> 0.5.0"}
]
end
```
Expand Down Expand Up @@ -90,7 +91,7 @@ Stellar relies on public key cryptography to ensure that transactions are secure
{public_key, secret_seed} = Stellar.KeyPair.from_secret_seed("SA33J3ACZZCV35FNSS655WXLIPTQOJS6WPQCKKYJSREDQY7KRLECEZSZ")
```

### Building transactions
### Transactions
[Transactions][stellar-docs-tx] are commands that modify the ledger state. They consist of a list of operations (up to 100) used to send payments, enter orders into the decentralized exchange, change settings on accounts, and authorize accounts to hold assets.

```elixir
Expand Down Expand Up @@ -656,6 +657,7 @@ Made with 💙 by [kommitters Open Source](https://kommit.co)
[sdk-tests]: https://github.com/kommitters/stellar_sdk/blob/main/test/tx_build
[hex]: https://hex.pm/packages/stellar_sdk
[stellar]: https://www.stellar.org/
[horizon-api]: https://developers.stellar.org/api/introduction
[http_client_spec]: https://github.com/kommitters/stellar_sdk/blob/main/lib/horizon/client/spec.ex
[stellar-docs-tx]: https://developers.stellar.org/docs/glossary/transactions
[stellar-docs-sequence-number]: https://developers.stellar.org/docs/glossary/transactions/#sequence-number
Expand Down
4 changes: 4 additions & 0 deletions lib/tx_build.ex
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ defmodule Stellar.TxBuild do
@impl true
def envelope(tx), do: impl().envelope(tx)

@impl true
def sign_envelope(base64_envelope, signatures),
do: impl().sign_envelope(base64_envelope, signatures)

@spec impl() :: atom()
defp impl do
Application.get_env(:stellar_sdk, :tx_build_impl, Stellar.TxBuild.Default)
Expand Down
15 changes: 15 additions & 0 deletions lib/tx_build/default.ex
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,19 @@ defmodule Stellar.TxBuild.Default do
|> TransactionEnvelope.to_xdr()
|> TransactionEnvelope.to_base64()
end

@impl true
def sign_envelope(tx_base64, []), do: tx_base64

def sign_envelope(tx_base64, [%Signature{} = signature | signatures]) do
tx_base64
|> sign_envelope(signature)
|> sign_envelope(signatures)
end

def sign_envelope(tx_base64, %Signature{} = signature) do
tx_base64
|> TransactionEnvelope.add_signature(signature)
|> TransactionEnvelope.to_base64()
end
end
1 change: 1 addition & 0 deletions lib/tx_build/spec.ex
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ defmodule Stellar.TxBuild.Spec do
@callback sign(tx(), signatures()) :: tx()
@callback build(tx()) :: tx()
@callback envelope(tx()) :: tx_envelope()
@callback sign_envelope(tx_envelope(), signatures()) :: tx_envelope()

@optional_callbacks add_memo: 2, set_base_fee: 2, set_time_bounds: 2, set_sequence_number: 2
end
18 changes: 18 additions & 0 deletions lib/tx_build/transaction_envelope.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ defmodule Stellar.TxBuild.TransactionEnvelope do

@behaviour Stellar.TxBuild.XDR

@type tx_base64 :: String.t()
@type signatures :: list(Signature.t())

@type t :: %__MODULE__{tx: Transaction.t(), signatures: signatures()}
Expand All @@ -34,10 +35,27 @@ defmodule Stellar.TxBuild.TransactionEnvelope do
|> TransactionEnvelope.new(envelope_type)
end

@spec add_signature(tx_base64 :: tx_base64, signature :: Signature.t()) ::
TransactionEnvelope.t()
def add_signature(tx_base64, %Signature{} = signature) do
with %TransactionEnvelope{envelope: envelope} = tx_envelope_xdr <- from_base64(tx_base64),
signatures <- TransactionSignature.sign_xdr(tx_envelope_xdr, signature) do
%{tx_envelope_xdr | envelope: %{envelope | signatures: signatures}}
end
end

@spec to_base64(tx_envelope_xdr :: TransactionEnvelope.t()) :: String.t()
def to_base64(%TransactionEnvelope{} = tx_envelope_xdr) do
tx_envelope_xdr
|> TransactionEnvelope.encode_xdr!()
|> Base.encode64()
end

@spec from_base64(tx_base64 :: tx_base64()) :: TransactionEnvelope.t()
def from_base64(tx_base64) do
tx_base64
|> Base.decode64!()
|> TransactionEnvelope.decode_xdr!()
|> elem(0)
end
end
43 changes: 36 additions & 7 deletions lib/tx_build/transaction_signature.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,55 @@ defmodule Stellar.TxBuild.TransactionSignature do
"""
alias Stellar.Network
alias Stellar.TxBuild.{Transaction, Signature}
alias StellarBase.XDR.{DecoratedSignatures, EnvelopeType, Hash, TransactionSignaturePayload}

alias StellarBase.XDR.{
DecoratedSignatures,
EnvelopeType,
Hash,
TransactionEnvelope,
TransactionSignaturePayload
}

alias StellarBase.XDR.Transaction, as: TransactionXDR
alias StellarBase.XDR.TransactionSignaturePayloadTaggedTransaction, as: TaggedTransaction

@type signatures :: list(Signature.t())

@spec sign(tx :: Transaction.t(), signatures :: signatures()) :: struct()
@spec sign(tx :: Transaction.t(), signatures :: signatures()) :: DecoratedSignatures.t()
def sign(%Transaction{} = tx, signatures) do
base_signature = base_signature(tx)
base_signature =
tx
|> Transaction.to_xdr()
|> base_signature()

signatures
|> Enum.map(&Signature.to_xdr(&1, base_signature))
|> DecoratedSignatures.new()
end

@spec base_signature(tx :: Transaction.t()) :: binary()
defp base_signature(%Transaction{} = tx) do
@spec sign_xdr(tx_envelope :: TransactionEnvelope.t(), signature :: Signature.t()) ::
DecoratedSignatures.t()
def sign_xdr(
%TransactionEnvelope{
envelope: %{
tx: tx_xdr,
signatures: %DecoratedSignatures{signatures: current_signatures}
}
},
%Signature{} = signature
) do
base_signature = base_signature(tx_xdr)

signature
|> Signature.to_xdr(base_signature)
|> (&DecoratedSignatures.new(current_signatures ++ [&1])).()
end

@spec base_signature(tx_xdr :: TransactionXDR.t()) :: binary()
defp base_signature(%TransactionXDR{} = tx_xdr) do
envelope_type = EnvelopeType.new(:ENVELOPE_TYPE_TX)

tx
|> Transaction.to_xdr()
tx_xdr
|> TaggedTransaction.new(envelope_type)
|> signature_payload()
end
Expand Down
4 changes: 2 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ defmodule Stellar.MixProject do
# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:stellar_base, "~> 0.5.0"},
{:stellar_base, "~> 0.6.0"},
{:ed25519, "~> 1.3"},
{:hackney, "~> 1.17", optional: true},
{:jason, "~> 1.0", optional: true},
Expand All @@ -50,7 +50,7 @@ defmodule Stellar.MixProject do

defp description do
"""
Elixir library that provides a client for interfacing with Horizon server REST endpoints.
Elixir Library to build Stellar transactions, as well as to interact with the REST endpoints of the Horizon server.
"""
end

Expand Down
2 changes: 1 addition & 1 deletion mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@
"nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"},
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
"stellar_base": {:hex, :stellar_base, "0.5.0", "41dab1d99b86f7ee8a86d07d1ddc59234f3be1df6a327479a7225b347425f546", [:mix], [{:crc, "~> 0.10.0", [hex: :crc, repo: "hexpm", optional: false]}, {:elixir_xdr, "~> 0.2.0", [hex: :elixir_xdr, repo: "hexpm", optional: false]}], "hexpm", "fa9f5c9bcc8607f2b80b49791541fab3835442f89b98f848bd86744873862cdc"},
"stellar_base": {:hex, :stellar_base, "0.6.0", "9f5088bd93b70f803fed809354a8b81f2aff02889db3d051d557dc4e79979492", [:mix], [{:crc, "~> 0.10.0", [hex: :crc, repo: "hexpm", optional: false]}, {:elixir_xdr, "~> 0.2.0", [hex: :elixir_xdr, repo: "hexpm", optional: false]}], "hexpm", "4865ac6c206ac7f96250c72e2323700545a905ba2c725cd557566eed2ac22b22"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
}
5 changes: 4 additions & 1 deletion test/support/fixtures/xdr.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Stellar.Test.Fixtures.XDR do
Mocks for XDR constructions.
"""

alias Stellar.Test.Fixtures.XDR.{Accounts, Transactions}
alias Stellar.Test.Fixtures.XDR.{Accounts, Transactions, TransactionEnvelope}

# accounts
defdelegate muxed_account(account_id), to: Accounts
Expand All @@ -12,4 +12,7 @@ defmodule Stellar.Test.Fixtures.XDR do
# transactions
defdelegate transaction(account_id), to: Transactions
defdelegate transaction_with_muxed_account(address), to: Transactions

# transactions envelope
defdelegate transaction_envelope(options \\ []), to: TransactionEnvelope
end
Loading

0 comments on commit 9e92c3d

Please sign in to comment.