Skip to content

Commit 6685e12

Browse files
authored
Merge pull request #2 from AIBlockOfficial/ci/publish-pypi
CI: add PyPI publish workflow; SDK: make Wallet.get_balance return IR…
2 parents 5e97b9f + b360fbb commit 6685e12

File tree

7 files changed

+826
-458
lines changed

7 files changed

+826
-458
lines changed

.github/workflows/publish.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Publish to PyPI
2+
3+
on:
4+
push:
5+
branches: [ "main" ]
6+
7+
concurrency:
8+
group: publish-pypi-${{ github.ref }}
9+
cancel-in-progress: false
10+
11+
jobs:
12+
build-and-publish:
13+
name: Build and publish
14+
runs-on: ubuntu-latest
15+
permissions:
16+
contents: read
17+
id-token: write
18+
steps:
19+
- name: Checkout repository
20+
uses: actions/checkout@v4
21+
22+
- name: Set up Python
23+
uses: actions/setup-python@v5
24+
with:
25+
python-version: "3.11"
26+
27+
- name: Install build backend
28+
run: |
29+
python -m pip install --upgrade pip
30+
python -m pip install build
31+
32+
- name: Build sdist and wheel
33+
run: python -m build
34+
35+
- name: Publish to PyPI
36+
uses: pypa/gh-action-pypi-publish@release/v1
37+
with:
38+
password: ${{ secrets.PYPI_API_TOKEN }}
39+
skip-existing: true
40+
41+

README.md

Lines changed: 86 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -10,78 +10,108 @@ pip install aiblock
1010

1111
## Quick Start
1212

13-
### Configuration Setup
13+
### Basic Blockchain Queries
1414

15-
The SDK uses environment variables for configuration:
15+
```python
16+
from aiblock.blockchain import BlockchainClient
1617

17-
```bash
18-
# Required environment variables
19-
export AIBLOCK_PASSPHRASE="your-secure-passphrase"
18+
# Initialize blockchain client
19+
client = BlockchainClient(
20+
storage_host='https://storage.aiblock.dev',
21+
mempool_host='https://mempool.aiblock.dev'
22+
)
23+
24+
# Query blockchain
25+
latest_block = client.get_latest_block()
26+
if latest_block.is_ok:
27+
print(f"Latest block: {latest_block.get_ok()['content']['block_num']}")
28+
29+
# Get specific block by number
30+
block = client.get_block_by_num(1)
31+
if block.is_ok:
32+
print(f"Block 1: {block.get_ok()['content']}")
2033

21-
# Optional environment variables (defaults shown)
22-
export AIBLOCK_STORAGE_HOST="https://storage.aiblock.dev"
23-
export AIBLOCK_MEMPOOL_HOST="https://mempool.aiblock.dev"
24-
export AIBLOCK_VALENCE_HOST="https://valence.aiblock.dev"
34+
# Get blockchain entry by hash
35+
entry = client.get_blockchain_entry('some_hash')
36+
37+
# Get transaction by hash
38+
transaction = client.get_transaction_by_hash('tx_hash')
39+
40+
# Get multiple transactions
41+
transactions = client.fetch_transactions(['hash1', 'hash2'])
42+
43+
# Get supply information (requires mempool host)
44+
total_supply = client.get_total_supply()
45+
issued_supply = client.get_issued_supply()
2546
```
2647

27-
### Basic Usage
48+
### Wallet Operations
2849

2950
```python
3051
from aiblock.wallet import Wallet
31-
from aiblock.blockchain import BlockchainClient
32-
from aiblock.config import get_config, validate_env_config
33-
34-
# Get and validate configuration
35-
config = get_config()
36-
error = validate_env_config(config)
37-
if error:
38-
print(f"Configuration error: {error}")
39-
exit(1)
4052

41-
# Initialize blockchain client
42-
blockchain_client = BlockchainClient(
43-
storage_host=config['storageHost'],
44-
mempool_host=config['mempoolHost']
45-
)
46-
47-
# Create and initialize wallet
53+
# Create wallet
4854
wallet = Wallet()
49-
seed_phrase = wallet.generate_seed_phrase()
50-
keypair = wallet.generate_keypair()
5155

52-
# Query blockchain
53-
latest_block = blockchain_client.get_latest_block()
54-
total_supply = blockchain_client.get_total_supply()
55-
issued_supply = blockchain_client.get_issued_supply()
56-
balance = blockchain_client.get_balance(keypair['address'])
56+
# Generate seed phrase
57+
seed_phrase = wallet.generate_seed_phrase()
58+
print(f"Seed phrase: {seed_phrase}")
59+
60+
# Initialize wallet from seed
61+
config = {
62+
'passphrase': 'your-secure-passphrase',
63+
'mempoolHost': 'https://mempool.aiblock.dev',
64+
'storageHost': 'https://storage.aiblock.dev',
65+
'valenceHost': 'https://valence.aiblock.dev'
66+
}
67+
68+
result = wallet.from_seed(seed_phrase, config)
69+
if result.is_ok:
70+
print(f"Wallet address: {wallet.get_address()}")
5771
```
5872

5973
## Features
6074

75+
### Blockchain Client
76+
- **get_latest_block()** - Get the latest block information
77+
- **get_block_by_num(block_num)** - Get a specific block by number
78+
- **get_blockchain_entry(hash)** - Get blockchain entry by hash
79+
- **get_transaction_by_hash(tx_hash)** - Get transaction details
80+
- **fetch_transactions(tx_hashes)** - Get multiple transactions
81+
- **get_total_supply()** - Get total token supply
82+
- **get_issued_supply()** - Get issued token supply
83+
6184
### Wallet Operations
6285
- Generate and manage seed phrases
6386
- Create and manage keypairs
6487
- Create and sign transactions
6588
- Create item assets
6689
- Check balances
90+
- 2WayPayment protocol support
91+
92+
## Configuration
6793

68-
### Blockchain Operations
69-
- Query latest block
70-
- Get block by number
71-
- Get blockchain entry by hash
72-
- Get total supply
73-
- Get issued supply
74-
- Get balance for address
94+
The SDK uses environment variables for configuration. Create a `.env` file:
7595

76-
## Example Usage
96+
```bash
97+
AIBLOCK_PASSPHRASE="your-secure-passphrase"
98+
AIBLOCK_STORAGE_HOST="https://storage.aiblock.dev"
99+
AIBLOCK_MEMPOOL_HOST="https://mempool.aiblock.dev"
100+
AIBLOCK_VALENCE_HOST="https://valence.aiblock.dev"
101+
```
77102

78-
See the [documentation](https://github.com/AIBlockOfficial/2Way.py/tree/main/docs) for more advanced usage and examples, including:
79-
- Wallet initialization
80-
- Keypair generation
81-
- Blockchain queries
82-
- Asset creation
83-
- Transaction creation
84-
- 2WayPayment protocol
103+
## Error Handling
104+
105+
All methods return `IResult` objects with proper error handling:
106+
107+
```python
108+
result = client.get_latest_block()
109+
if result.is_ok:
110+
data = result.get_ok()
111+
print(f"Success: {data}")
112+
else:
113+
print(f"Error: {result.error_message}")
114+
```
85115

86116
## Development
87117

@@ -90,6 +120,14 @@ See the [documentation](https://github.com/AIBlockOfficial/2Way.py/tree/main/doc
90120
3. Install test dependencies: `pip install -r requirements-test.txt`
91121
4. Run tests: `pytest`
92122

123+
All 68 tests pass, ensuring reliability and compatibility.
124+
125+
## Documentation
126+
127+
- [API Reference](docs/api-reference.md) - Complete API documentation
128+
- [Examples](docs/examples.md) - Usage examples and patterns
129+
- [Troubleshooting](docs/troubleshooting.md) - Common issues and solutions
130+
93131
## Contributing
94132

95133
We welcome contributions! Please feel free to submit a Pull Request.

aiblock/wallet.py

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -599,35 +599,51 @@ def get_headers(self) -> Dict[str, str]:
599599
'Nonce': get_random_string(32)
600600
}
601601

602-
def get_balance(self) -> Dict[str, Any]:
603-
"""Get balance for the current address.
604-
602+
def get_balance(self) -> IResult[Dict[str, Any]]:
603+
"""Get balance for the current address as an IResult for consistency."""
604+
try:
605+
if not self.current_keypair:
606+
return IResult.err(IErrorInternal.WalletNotInitialized, "Wallet not initialized")
607+
608+
# Initialize network if needed
609+
if not self.routes_initialized:
610+
init_result = self.init_network(self.config)
611+
if init_result.is_err:
612+
return IResult.err(IErrorInternal.UnableToInitializeNetwork, init_result.error_message)
613+
614+
balance_result = self.fetch_balance([self.current_keypair.address])
615+
if balance_result.is_err:
616+
return IResult.err(IErrorInternal.UnableToFetchBalance, balance_result.error_message)
617+
618+
return IResult.ok(balance_result.get_ok())
619+
except Exception as e:
620+
logger.error(f"Error getting balance: {str(e)}")
621+
return IResult.err(IErrorInternal.InternalError, str(e))
622+
623+
def get_balance_result(self) -> IResult[Dict[str, Any]]:
624+
"""Get balance for the current address as an IResult for consistency.
625+
605626
Returns:
606-
Dict[str, Any]: Balance information
607-
608-
Raises:
609-
RuntimeError: If wallet is not initialized
627+
IResult[Dict[str, Any]]: Success with balance dict, or error with reason.
610628
"""
611629
try:
612630
if not self.current_keypair:
613-
raise RuntimeError("Wallet not initialized")
631+
return IResult.err(IErrorInternal.WalletNotInitialized, "Wallet not initialized")
614632

615633
# Initialize network if needed
616634
if not self.routes_initialized:
617635
init_result = self.init_network(self.config)
618636
if init_result.is_err:
619-
raise RuntimeError("Failed to initialize network")
637+
return IResult.err(IErrorInternal.UnableToInitializeNetwork, init_result.error_message)
620638

621-
# Get balance
622639
balance_result = self.fetch_balance([self.current_keypair.address])
623640
if balance_result.is_err:
624-
raise RuntimeError("Failed to fetch balance")
625-
626-
return balance_result.get_ok()
641+
return IResult.err(IErrorInternal.UnableToFetchBalance, balance_result.error_message)
627642

643+
return IResult.ok(balance_result.get_ok())
628644
except Exception as e:
629645
logger.error(f"Error getting balance: {str(e)}")
630-
raise
646+
return IResult.err(IErrorInternal.InternalError, str(e))
631647

632648
def create_item_asset(
633649
self,

0 commit comments

Comments
 (0)