Skip to content
Merged
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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# turbo-python-sdk

## 0.1.0

### Added

- `SolanaSigner` for signing data items with a Solana (ed25519) wallet. Accepts a Solana CLI `id.json` (via `SolanaSigner.from_file()` or a 64-int list), a base58-encoded secret key, a raw 64-byte secret key, or a 32-byte seed; the wallet address is the base58 of the ed25519 public key. Uses ANS-104 signature type 2 (raw ED25519), which Turbo bills as the `solana` token. Verified end-to-end against the upload backend and cross-checked byte-for-byte with `@dha-team/arbundles`.
- `TOKEN_MAP` entry mapping signature type 2 to the `solana` token so `Turbo(SolanaSigner(...))` initializes correctly.

### Fixed

- Aligned `pyproject.toml` version (was `0.0.6`) with `turbo_sdk.__version__` (`0.1.0`), which had drifted apart.

## 0.0.6

### Added
Expand Down
50 changes: 48 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,30 @@ result = turbo.upload(b"Hello from Arweave!", tags=[
print(f"✅ Uploaded! URI: ar://{result.id}")
```

#### Solana Usage

```python
from turbo_sdk import Turbo, SolanaSigner

# Load a Solana CLI keypair (id.json: JSON array of 64 ints)
signer = SolanaSigner.from_file("~/.config/solana/id.json")

# Or construct directly from a raw 64-byte secret key, a 32-byte seed,
# a CLI keypair list/JSON string, or a base58-encoded secret key:
# signer = SolanaSigner(secret_bytes)
# signer = SolanaSigner("4Nd1m...") # base58 secret key

# Create Turbo client (billed as the "solana" token)
turbo = Turbo(signer, network="mainnet")

# Upload data
result = turbo.upload(b"Hello from Solana!", tags=[
{"name": "Content-Type", "value": "text/plain"}
])

print(f"✅ Uploaded! URI: ar://{result.id}")
```

## APIs

### Core Classes
Expand All @@ -67,7 +91,7 @@ Main client for interacting with Turbo services.

**Parameters:**

- `signer`: Either `EthereumSigner` or `ArweaveSigner` instance
- `signer`: An `EthereumSigner`, `ArweaveSigner`, or `SolanaSigner` instance
- `network`: `"mainnet"` or `"testnet"` (default: `"mainnet"`)
- `upload_url`: Optional custom upload service URL (overrides network default)
- `payment_url`: Optional custom payment service URL (overrides network default)
Expand Down Expand Up @@ -234,9 +258,31 @@ signer = ArweaveSigner({
})
```

#### `SolanaSigner(secret_key)`

Solana signer using ed25519 signatures (ANS-104 signature type 2). The wallet
address is the base58 encoding of the 32-byte ed25519 public key. Turbo bills
uploads from this signer as the `solana` token.

**Parameters:**

- `secret_key`: One of:
- a Solana CLI keypair (`id.json` contents) as a `list` of 64 ints or its JSON string
- a raw 64-byte secret key (`bytes`/`bytearray`, seed ‖ public key)
- a raw 32-byte seed (`bytes`/`bytearray`)
- a base58-encoded secret key (`str`)

```python
# From a CLI keypair file:
signer = SolanaSigner.from_file("~/.config/solana/id.json")

# Or directly:
signer = SolanaSigner(secret_key_bytes)
```

#### Signer Methods

Both signers provide:
All signers provide:

##### `get_wallet_address() -> str`

Expand Down
2 changes: 1 addition & 1 deletion examples/arweave_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def main():
print(f"🔗 URI: ar://{result.id}")
print(f"💸 Cost: {result.winc} winc")
print(f"🌐 Gateway URL: https://arweave.net/{result.id}")

# v0.0.6 fields
if result.timestamp:
print(f"⏰ Timestamp: {result.timestamp}")
Expand Down
62 changes: 62 additions & 0 deletions examples/solana_upload.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env python3
"""
Example: Upload data using a Solana wallet
"""

from turbo_sdk import Turbo, SolanaSigner


def main():
# Solana secret key. Any of these forms work:
# - a Solana CLI ``id.json`` (use ``SolanaSigner.from_file("id.json")``)
# - a base58-encoded secret key (Phantom "export private key")
# - raw 64-byte secret key (seed||pubkey) or a 32-byte seed
# Replace with your actual key (base58 shown here).
secret_key = "your-base58-encoded-solana-secret-key"

# Create signer and Turbo client
signer = SolanaSigner(secret_key)
turbo = Turbo(signer, network="mainnet") # or "testnet"

print(f"🔑 Connected with Solana signer ({signer.get_wallet_address()})")

# Check balance
try:
balance = turbo.get_balance()
print(f"💰 Balance: {balance.winc} winc")
except Exception as e:
print(f"⚠️ Could not fetch balance: {e}")

# Prepare data to upload
data = b"Hello, Turbo from Solana!"

# Get upload cost
try:
cost = turbo.get_upload_price(len(data))
print(f"💸 Upload cost: {cost} winc")
except Exception as e:
print(f"⚠️ Could not fetch price: {e}")

# Upload data (files under 100 KiB are free-tier)
try:
result = turbo.upload(
data,
tags=[
{"name": "Content-Type", "value": "text/plain"},
{"name": "App-Name", "value": "Turbo-SDK-Python"},
{"name": "Source", "value": "Solana"},
],
)

print("✅ Upload successful!")
print(f"📄 Transaction ID: {result.id}")
print(f"💸 Cost: {result.winc} winc")
print(f"🚀 Data caches: {result.data_caches}")
print(f"🌐 Gateway URL: https://arweave.net/{result.id}")

except Exception as e:
print(f"❌ Upload failed: {e}")


if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "turbo-sdk"
version = "0.0.6"
version = "0.1.0"
description = "Python SDK for interacting with the Ardrive Turbo Upload and Payment Service"
readme = "README.md"
license = {text = "MIT"}
Expand Down
Loading
Loading