Skip to content

Commit 88f07bd

Browse files
committed
Merge branch 'main' into aliel-fix-cosmos
2 parents f5d46ad + dbc40a0 commit 88f07bd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+4333
-170
lines changed

.github/workflows/build-wheels.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ jobs:
4141
if: startsWith(matrix.os, 'macos-')
4242
run: |
4343
brew update
44-
brew tap cuber/homebrew-libsecp256k1
45-
brew install libsecp256k1
44+
brew install secp256k1
4645
4746
- name: Install required system packages only for Ubuntu Linux
4847
if: startsWith(matrix.os, 'ubuntu-')

.github/workflows/pytest.yml

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,15 @@ on:
66
branches:
77
- main
88
schedule:
9-
# Run every night at 04:00 (GitHub Actions timezone)
10-
# in order to catch when unfrozen dependency updates
11-
# break the use of the library.
129
- cron: '4 0 * * *'
1310

1411
jobs:
1512
tests:
1613
strategy:
1714
fail-fast: false
1815
matrix:
19-
python-version: [ "3.9", "3.10", "3.11", "3.12" ]
20-
os: [ubuntu-22.04, ubuntu-24.04]
16+
python-version: ["3.9", "3.10", "3.11", "3.12"]
17+
os: [ubuntu-22.04, ubuntu-24.04, macos-14, macos-15]
2118
runs-on: ${{ matrix.os }}
2219

2320
steps:
@@ -26,15 +23,24 @@ jobs:
2623
with:
2724
python-version: ${{ matrix.python-version }}
2825

29-
- run: |
26+
- name: "apt-get install"
27+
run: |
3028
sudo apt-get update
31-
sudo apt-get install -y python3-pip libsodium-dev
29+
sudo apt-get install -y python3-pip libsodium-dev libgmp-dev
30+
if: runner.os == 'Linux'
3231

3332
- run: |
33+
brew install libsodium
34+
echo "DYLD_LIBRARY_PATH=$(brew --prefix libsodium)/lib" >> $GITHUB_ENV
35+
if: runner.os == 'macOS'
36+
37+
- name: "Install Hatch"
38+
run: |
3439
python3 -m venv /tmp/venv
3540
/tmp/venv/bin/python -m pip install --upgrade pip hatch coverage
3641
37-
- run: |
42+
- name: "Run Tests"
43+
run: |
3844
/tmp/venv/bin/pip freeze
3945
/tmp/venv/bin/hatch run testing:pip freeze
4046
/tmp/venv/bin/hatch run testing:test

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ Using some chains may also require installing `libgmp3-dev`.
2121
### macOs
2222
This project does not support Python 3.12 on macOS. Please use Python 3.11 instead.
2323
```shell
24-
$ brew tap cuber/homebrew-libsecp256k1
25-
$ brew install libsecp256k1
24+
$ brew install secp256k1
2625
```
2726

2827
## Installation

pyproject.toml

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,20 @@ dynamic = [ "version" ]
3030
dependencies = [
3131
"aiohttp>=3.8.3",
3232
"aioresponses>=0.7.6",
33-
"aleph-message>=0.6",
34-
"aleph-superfluid>=0.2.1",
33+
"aleph-message>=1.0.4",
34+
"aleph-superfluid>=0.3",
3535
"base58==2.1.1", # Needed now as default with _load_account changement
36-
"coincurve; python_version<'3.11'",
37-
"coincurve>=19; python_version>='3.11'",
38-
"eth-abi>=4; python_version>='3.11'",
39-
"eth-typing==4.3.1",
36+
"coincurve; python_version>='3.9'",
37+
"coincurve>=19; python_version>='3.9'",
38+
"eth-abi>=5.0.1; python_version>='3.9'",
39+
"eth-typing>=5.0.1",
4040
"jwcrypto==1.5.6",
41+
"pydantic>=2,<3",
42+
"pydantic-settings>=2",
4143
"pynacl==1.5", # Needed now as default with _load_account changement
4244
"python-magic",
4345
"typing-extensions",
44-
"web3==6.3",
46+
"web3>=7.10",
4547
]
4648

4749
optional-dependencies.all = [
@@ -80,8 +82,7 @@ optional-dependencies.substrate = [
8082
"substrate-interface",
8183
]
8284
optional-dependencies.tezos = [
83-
"aleph-pytezos==3.13.4",
84-
"pynacl",
85+
"pytezos-crypto==3.13.4.1",
8586
]
8687
urls.Documentation = "https://aleph.im/"
8788
urls.Homepage = "https://github.com/aleph-im/aleph-sdk-python"

src/aleph/sdk/account.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from aleph.sdk.chains.remote import RemoteAccount
1313
from aleph.sdk.chains.solana import SOLAccount
1414
from aleph.sdk.chains.substrate import DOTAccount
15+
from aleph.sdk.chains.svm import SVMAccount
1516
from aleph.sdk.conf import load_main_configuration, settings
1617
from aleph.sdk.evm_utils import get_chains_with_super_token
1718
from aleph.sdk.types import AccountFromPrivateKey
@@ -22,21 +23,29 @@
2223

2324
chain_account_map: Dict[Chain, Type[T]] = { # type: ignore
2425
Chain.ARBITRUM: EVMAccount,
26+
Chain.AURORA: EVMAccount,
2527
Chain.AVAX: ETHAccount,
2628
Chain.BASE: ETHAccount,
2729
Chain.BLAST: EVMAccount,
2830
Chain.BOB: EVMAccount,
31+
Chain.BSC: EVMAccount,
2932
Chain.CYBER: EVMAccount,
3033
Chain.DOT: DOTAccount,
34+
Chain.ECLIPSE: SVMAccount,
3135
Chain.ETH: ETHAccount,
3236
Chain.FRAXTAL: EVMAccount,
37+
Chain.INK: EVMAccount,
3338
Chain.LINEA: EVMAccount,
3439
Chain.LISK: EVMAccount,
3540
Chain.METIS: EVMAccount,
3641
Chain.MODE: EVMAccount,
42+
Chain.NEO: EVMAccount,
3743
Chain.OPTIMISM: EVMAccount,
3844
Chain.POL: EVMAccount,
3945
Chain.SOL: SOLAccount,
46+
Chain.SOMNIA: EVMAccount,
47+
Chain.SONIC: EVMAccount,
48+
Chain.UNICHAIN: EVMAccount,
4049
Chain.WORLDCHAIN: EVMAccount,
4150
Chain.ZORA: EVMAccount,
4251
Chain.CSDK: CSDKAccount,

src/aleph/sdk/chains/common.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ async def sign_message(self, message: Dict) -> Dict:
7373
message = self._setup_sender(message)
7474
signature = await self.sign_raw(get_verification_buffer(message))
7575
message["signature"] = signature.hex()
76+
7677
return message
7778

7879
@abstractmethod

src/aleph/sdk/chains/ethereum.py

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import base64
33
from decimal import Decimal
44
from pathlib import Path
5-
from typing import Awaitable, Optional, Union
5+
from typing import Awaitable, Dict, Optional, Union
66

77
from aleph_message.models import Chain
88
from eth_account import Account # type: ignore
@@ -11,7 +11,8 @@
1111
from eth_keys.exceptions import BadSignature as EthBadSignatureError
1212
from superfluid import Web3FlowInfo
1313
from web3 import Web3
14-
from web3.middleware import geth_poa_middleware
14+
from web3.exceptions import ContractCustomError
15+
from web3.middleware import ExtraDataToPOAMiddleware
1516
from web3.types import TxParams, TxReceipt
1617

1718
from aleph.sdk.exceptions import InsufficientFundsError
@@ -21,7 +22,6 @@
2122
from ..connectors.superfluid import Superfluid
2223
from ..evm_utils import (
2324
BALANCEOF_ABI,
24-
MIN_ETH_BALANCE,
2525
MIN_ETH_BALANCE_WEI,
2626
FlowUpdate,
2727
from_wei_token,
@@ -80,6 +80,22 @@ async def sign_raw(self, buffer: bytes) -> bytes:
8080
sig = self._account.sign_message(msghash)
8181
return sig["signature"]
8282

83+
async def sign_message(self, message: Dict) -> Dict:
84+
"""
85+
Returns a signed message from an aleph.im message.
86+
Args:
87+
message: Message to sign
88+
Returns:
89+
Dict: Signed message
90+
"""
91+
signed_message = await super().sign_message(message)
92+
93+
# Apply that fix as seems that sometimes the .hex() method doesn't add the 0x str at the beginning
94+
if not str(signed_message["signature"]).startswith("0x"):
95+
signed_message["signature"] = "0x" + signed_message["signature"]
96+
97+
return signed_message
98+
8399
def connect_chain(self, chain: Optional[Chain] = None):
84100
self.chain = chain
85101
if self.chain:
@@ -88,7 +104,7 @@ def connect_chain(self, chain: Optional[Chain] = None):
88104
self._provider = Web3(Web3.HTTPProvider(self.rpc))
89105
if chain == Chain.BSC:
90106
self._provider.middleware_onion.inject(
91-
geth_poa_middleware, "geth_poa", layer=0
107+
ExtraDataToPOAMiddleware, "geth_poa", layer=0
92108
)
93109
else:
94110
self.chain_id = None
@@ -103,14 +119,34 @@ def connect_chain(self, chain: Optional[Chain] = None):
103119
def switch_chain(self, chain: Optional[Chain] = None):
104120
self.connect_chain(chain=chain)
105121

106-
def can_transact(self, block=True) -> bool:
107-
balance = self.get_eth_balance()
108-
valid = balance > MIN_ETH_BALANCE_WEI if self.chain else False
122+
def can_transact(self, tx: TxParams, block=True) -> bool:
123+
balance_wei = self.get_eth_balance()
124+
try:
125+
assert self._provider is not None
126+
127+
estimated_gas = self._provider.eth.estimate_gas(tx)
128+
129+
gas_price = tx.get("gasPrice", self._provider.eth.gas_price)
130+
131+
if "maxFeePerGas" in tx:
132+
max_fee = tx["maxFeePerGas"]
133+
total_fee_wei = estimated_gas * max_fee
134+
else:
135+
total_fee_wei = estimated_gas * gas_price
136+
137+
total_fee_wei = int(total_fee_wei * 1.2)
138+
139+
except ContractCustomError:
140+
total_fee_wei = MIN_ETH_BALANCE_WEI # Fallback if estimation fails
141+
142+
required_fee_wei = total_fee_wei + (tx.get("value", 0))
143+
144+
valid = balance_wei > required_fee_wei if self.chain else False
109145
if not valid and block:
110146
raise InsufficientFundsError(
111147
token_type=TokenType.GAS,
112-
required_funds=MIN_ETH_BALANCE,
113-
available_funds=float(from_wei_token(balance)),
148+
required_funds=float(from_wei_token(required_fee_wei)),
149+
available_funds=float(from_wei_token(balance_wei)),
114150
)
115151
return valid
116152

@@ -120,15 +156,15 @@ async def _sign_and_send_transaction(self, tx_params: TxParams) -> str:
120156
@param tx_params - Transaction parameters
121157
@returns - str - Transaction hash
122158
"""
123-
self.can_transact()
124159

125160
def sign_and_send() -> TxReceipt:
126161
if self._provider is None:
127162
raise ValueError("Provider not connected")
128163
signed_tx = self._provider.eth.account.sign_transaction(
129164
tx_params, self._account.key
130165
)
131-
tx_hash = self._provider.eth.send_raw_transaction(signed_tx.rawTransaction)
166+
167+
tx_hash = self._provider.eth.send_raw_transaction(signed_tx.raw_transaction)
132168
tx_receipt = self._provider.eth.wait_for_transaction_receipt(
133169
tx_hash, settings.TX_TIMEOUT
134170
)

src/aleph/sdk/chains/svm.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from typing import Optional
2+
3+
from aleph_message.models import Chain
4+
5+
from .solana import SOLAccount
6+
7+
8+
class SVMAccount(SOLAccount):
9+
def __init__(self, private_key: bytes, chain: Optional[Chain] = None):
10+
super().__init__(private_key=private_key)
11+
# Same as EVM ACCOUNT need to decided if we want to send the specified chain or always use SOL
12+
if chain:
13+
self.CHAIN = chain

src/aleph/sdk/chains/tezos.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
from pathlib import Path
33
from typing import Dict, Optional, Union
44

5-
from aleph_pytezos.crypto.key import Key
65
from nacl.public import SealedBox
76
from nacl.signing import SigningKey
7+
from pytezos_crypto.key import Key
88

99
from .common import BaseAccount, get_fallback_private_key, get_verification_buffer
1010

0 commit comments

Comments
 (0)