Skip to content
Merged

V0.23 #385

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .credo.exs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
checks: [
{Credo.Check.Readability.AliasOrder, false},
{Credo.Check.Readability.Specs, []},
{Credo.Check.Refactor.FunctionArity, max_arity: 10}
{Credo.Check.Refactor.FunctionArity, max_arity: 10},
{Credo.Check.Consistency.SpaceAroundOperators, false}
]
}
]
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ permissions: # added using https://github.com/step-security/secure-workflows
jobs:
publish:
name: Publish Release to HEX PM
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
strategy:
matrix:
otp: ['23.3']
elixir: ['1.12']
otp: ['27.2']
elixir: ['1.17']
env:
HEX_API_KEY: ${{ secrets.HEX_API_KEY }}
steps:
Expand All @@ -31,11 +31,11 @@ jobs:
builds.hex.pm:443

- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: erlef/setup-elixir@904c511e63061a8f501ae4b081ce2c0e9cfc70ab # v1.17.4
- uses: erlef/setup-beam@v1
with:
otp-version: ${{ matrix.otp }}
elixir-version: ${{ matrix.elixir }}
- uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1
- uses: actions/cache@v4
with:
path: deps
key: ${{ runner.os }}-mix-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}
Expand Down
13 changes: 7 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ permissions:
jobs:
tests:
name: Run tests
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
strategy:
matrix:
otp: ['23.3', '24.3']
elixir: ['1.12', '1.13']
include:
- otp: '26.2'
elixir: '1.16'
env:
MIX_ENV: test
steps:
Expand All @@ -32,11 +33,11 @@ jobs:
*.hex.pm:443

- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: erlef/setup-beam@904c511e63061a8f501ae4b081ce2c0e9cfc70ab # v1.17.4
- uses: erlef/setup-beam@v1
with:
otp-version: ${{ matrix.otp }}
elixir-version: ${{ matrix.elixir }}
- uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1
- uses: actions/cache@v4
with:
path: deps
key: ${{ runner.os }}-mix-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}
Expand All @@ -59,7 +60,7 @@ jobs:

finish:
needs: tests
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## 0.23.0 (02.06.2026)

- Support Protocol 22, 23, and 26 features.
- Upgrade `stellar_base` dependency to `~> 0.17.0`.
- Add `CreateContractArgsV2` for Smart Contract Constructor support (CAP-0058).
- Update `HostFunction` to support `:create_contract_v2` host function type.

## 0.22.0 (16.08.2024)

- Add hash to handle transaction timeout response. See [PR #374](https://github.com/kommitters/stellar_sdk/pull/374)
Expand Down
118 changes: 118 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Development Commands

### Core Development Tasks
- **Install dependencies**: `mix deps.get`
- **Run tests**: `mix test`
- **Run single test**: `mix test test/path/to/test_file.exs`
- **Run tests with specific pattern**: `mix test --grep "pattern"`
- **Format code**: `mix format`
- **Lint code**: `mix credo` (with strict mode enabled)
- **Type checking**: `mix dialyzer` (Dialyxir for static analysis)
- **Generate docs**: `mix docs`
- **Check test coverage**: `mix coveralls` or `mix coveralls.html`

### Mix Project Configuration
- Elixir version requirement: `~> 1.12`
- Test coverage tool: ExCoveralls
- Code linting: Credo (strict mode, max function arity of 10)
- Static analysis: Dialyxir
- Documentation: ExDoc

## Code Architecture

### High-Level Structure
This is the **Elixir Stellar SDK**, a comprehensive library for interacting with the Stellar network. The codebase is organized around two main components:

1. **`TxBuild`** (`lib/tx_build/`) - Transaction construction and signing
2. **`Horizon`** (`lib/horizon/`) - HTTP client for Horizon API interactions

### Core Modules

#### Transaction Building (`lib/tx_build/`)
- **`Stellar.TxBuild`** - Main transaction builder API with behavior pattern
- **`Stellar.TxBuild.Default`** - Default implementation of transaction building
- **Operations** - Individual operation types (Payment, CreateAccount, etc.)
- **Components** - Account, Memo, Signature, Preconditions, TimeBounds, etc.
- Uses behavior pattern for pluggable implementations via `:tx_build_impl` config

#### Horizon Client (`lib/horizon/`)
- **Resource modules** - Accounts, Transactions, Operations, Ledgers, etc.
- **Client abstraction** - HTTP client interface with `:http_client_impl` config
- **Server configuration** - Public, testnet, futurenet, and custom endpoints
- **Collection handling** - Pagination support with HAL format links
- **Error handling** - Structured error responses and mapping

#### Utilities
- **`Stellar.KeyPair`** - Key generation and management (Ed25519)
- **`Stellar.Network`** - Network passphrases (testnet, public, etc.)

### Key Design Patterns

#### Behavior Pattern
The codebase uses Elixir behaviors extensively:
- `Stellar.TxBuild.Spec` - Defines transaction building interface
- `Stellar.KeyPair.Spec` - Defines key pair operations interface
- Implementation swappable via application configuration

#### Configuration-Based Implementation Injection
- `:tx_build_impl` - Transaction building implementation (defaults to `Stellar.TxBuild.Default`)
- `:http_client_impl` - HTTP client implementation (defaults to hackney)
- `:hackney_opts` - HTTP client options

#### Resource-Collection Pattern
Horizon resources follow a consistent pattern:
- Individual resource retrieval (e.g., `retrieve/2`)
- Collection listing with filtering (e.g., `all/2`)
- Related resource listing (e.g., `list_transactions/3`)
- Pagination handled via HAL links converted to functions

## Important Development Notes

### Network Configuration
- Default network is **testnet** (`Stellar.Network.testnet_passphrase/0`)
- Production requires explicit **public network** configuration
- Support for futurenet and custom networks

### Protocol Version Support
The SDK supports Stellar Protocol versions 18-21 with specific version requirements:
- Protocol 20: requires SDK v0.20+
- Protocol 21: requires SDK v0.21.2+

### Key Dependencies
- **stellar_base**: Core Stellar primitives (~> 0.16)
- **hackney**: Default HTTP client (~> 1.17)
- **jason**: JSON encoding/decoding (~> 1.0)
- **ed25519**: Cryptographic operations (~> 1.3)

### Testing Structure
- Tests mirror the `lib/` structure exactly
- Heavy use of mocking for HTTP interactions
- Comprehensive coverage of transaction building scenarios
- Integration tests for Horizon client functionality

### Code Quality Standards
- **Credo**: Strict mode enabled, function arity limited to 10
- **Formatter**: Standard Elixir formatting rules
- **Dialyxir**: Static type analysis for better code quality
- **ExCoveralls**: Test coverage reporting and tracking

### Stellar-Specific Concepts
When working with this codebase, understand these Stellar concepts:
- **Muxed accounts**: Virtual accounts under a real account with 64-bit ID
- **Operations**: Atomic units of change (payments, offers, account creation)
- **Preconditions**: Time bounds, ledger bounds, sequence number constraints
- **Signatures**: Ed25519, hash(x), and signed payload signature types
- **Transaction envelopes**: Signed transaction containers for network submission

## Recommended Workflow

1. **Transaction Building**: Start with `Stellar.TxBuild.new/2`, add operations, set sequence numbers, sign, and generate envelope
2. **Horizon Queries**: Use appropriate resource modules (`Accounts`, `Transactions`, etc.) with server configuration
3. **Testing**: Write tests in corresponding test directory structure, mock HTTP calls for Horizon interactions
4. **Documentation**: Follow existing documentation patterns, especially for public APIs

This SDK is production-ready with extensive test coverage and follows Stellar network best practices.
46 changes: 46 additions & 0 deletions GEMINI.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Gemini Code Assistant Context

## Project Overview

This project is the Elixir Stellar SDK, a library for interacting with the Stellar network. It allows developers to build, sign, and encode Stellar transactions and operations, as well as query the Horizon API for ledger information.

The SDK is composed of two main components:

* **TxBuild**: For constructing Stellar transactions. It provides a comprehensive API to create and customize transactions, including adding operations, memos, preconditions, and signatures.
* **Horizon**: A client for the Horizon API, which allows developers to query for information about accounts, transactions, operations, ledgers, and more.

The project is built with Elixir and uses `mix` for dependency management and running tasks.

## Building and Running

### Dependencies

Dependencies are managed with `mix` and are listed in the `mix.exs` file. Key dependencies include:

* `stellar_base`: For Stellar XDR data structures.
* `ed25519`: For cryptographic signing.
* `hackney`: As the default HTTP client.
* `jason`: For JSON parsing.

### Key Commands

* **Install dependencies:**
```bash
mix deps.get
```
* **Run tests:**
```bash
mix test
```
* **Format code:**
```bash
mix format
```

## Development Conventions

* **Testing**: The project has a comprehensive test suite in the `test` directory. All new contributions should include corresponding tests.
* **Formatting**: Code should be formatted using `mix format`.
* **Branching**: Development should be done on topic branches, not directly on the `main` branch.
* **Commits**: Commit messages should be descriptive and follow the guidelines in the `CONTRIBUTING.md` file.
* **Pull Requests**: Pull requests should be focused on a single issue and should be rebased against the `main` branch.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ This library is aimed at developers building Elixir applications that interact w
| 19 | >= v0.9 |
| 20 | >= v0.20 |
| 21 | >= v0.21.2 |
| 22/23/26 | >= v0.23.0 |

## Documentation
The **Stellar SDK** is composed of two complementary components: **`TxBuild`** + **`Horizon`**.
Expand All @@ -36,7 +37,7 @@ The **Stellar SDK** is composed of two complementary components: **`TxBuild`** +
```elixir
def deps do
[
{:stellar_sdk, "~> 0.22.0"}
{:stellar_sdk, "~> 0.23.0"}
]
end
```
Expand Down
97 changes: 97 additions & 0 deletions lib/tx_build/create_contract_args_v2.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
defmodule Stellar.TxBuild.CreateContractArgsV2 do
@moduledoc """
`CreateContractArgsV2` struct definition for Protocol 22+.
"""
alias StellarBase.XDR.{CreateContractArgsV2, SCValList}
alias Stellar.TxBuild.{ContractExecutable, ContractIDPreimage, SCVal}

@behaviour Stellar.TxBuild.XDR

@type contract_id_preimage :: ContractIDPreimage.t()
@type contract_executable :: ContractExecutable.t()
@type constructor_args :: list(SCVal.t())
@type error :: {:error, atom()}
@type validation :: {:ok, any()} | error()

@type t :: %__MODULE__{
contract_id_preimage: contract_id_preimage(),
contract_executable: contract_executable(),
constructor_args: constructor_args()
}

defstruct [:contract_id_preimage, :contract_executable, :constructor_args]

@impl true
def new(args, opts \\ [])

def new(args, _opts) when is_list(args) do
contract_id_preimage = Keyword.get(args, :contract_id_preimage)
contract_executable = Keyword.get(args, :contract_executable)
constructor_args = Keyword.get(args, :constructor_args, [])

with {:ok, contract_id_preimage} <-
validate_contract_id_preimage(contract_id_preimage),
{:ok, contract_executable} <- validate_contract_executable(contract_executable),
{:ok, constructor_args} <- validate_constructor_args(constructor_args) do
%__MODULE__{
contract_id_preimage: contract_id_preimage,
contract_executable: contract_executable,
constructor_args: constructor_args
}
end
end

def new(_value, _opts), do: {:error, :invalid_args}

@impl true
def to_xdr(%__MODULE__{
contract_id_preimage: contract_id_preimage,
contract_executable: contract_executable,
constructor_args: constructor_args
}) do
contract_executable_xdr = ContractExecutable.to_xdr(contract_executable)
contract_id_preimage_xdr = ContractIDPreimage.to_xdr(contract_id_preimage)

constructor_args_xdr =
constructor_args
|> Enum.map(&SCVal.to_xdr/1)
|> SCValList.new()

CreateContractArgsV2.new(
contract_id_preimage_xdr,
contract_executable_xdr,
constructor_args_xdr
)
end

def to_xdr(_struct), do: {:error, :invalid_struct}

@spec validate_contract_id_preimage(contract_id_preimage :: contract_id_preimage()) ::
validation()
defp validate_contract_id_preimage(%ContractIDPreimage{} = contract_id_preimage),
do: {:ok, contract_id_preimage}

defp validate_contract_id_preimage(_contract_id_preimage),
do: {:error, :invalid_contract_id_preimage}

@spec validate_contract_executable(contract_executable :: contract_executable()) ::
validation()
defp validate_contract_executable(%ContractExecutable{} = contract_executable),
do: {:ok, contract_executable}

defp validate_contract_executable(_contract_executable),
do: {:error, :invalid_contract_executable}

@spec validate_constructor_args(constructor_args :: constructor_args()) :: validation()
defp validate_constructor_args(constructor_args) when is_list(constructor_args) do
if Enum.all?(constructor_args, &is_sc_val?/1),
do: {:ok, constructor_args},
else: {:error, :invalid_constructor_args}
end

defp validate_constructor_args(_constructor_args), do: {:error, :invalid_constructor_args}

@spec is_sc_val?(value :: any()) :: boolean()
defp is_sc_val?(%SCVal{}), do: true
defp is_sc_val?(_), do: false
end
Loading
Loading