Skip to content

Commit 5028e86

Browse files
authored
Merge branch 'main' into 177-upgrade-pydantic-version
2 parents 00177ae + a1c7313 commit 5028e86

File tree

7 files changed

+153
-20
lines changed

7 files changed

+153
-20
lines changed

.github/workflows/build-wheels.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
strategy:
1414
fail-fast: false
1515
matrix:
16-
os: [macos-12, macos-13, macos-14, ubuntu-22.04, ubuntu-24.04]
16+
os: [macos-13, macos-14, ubuntu-22.04, ubuntu-24.04]
1717
runs-on: ${{ matrix.os }}
1818

1919
steps:

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ MANIFEST
4747

4848
# Per-project virtualenvs
4949
.venv*/
50+
venv/*
5051
**/device.key
5152

5253
# environment variables

src/aleph/sdk/account.py

+35-11
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77

88
from aleph.sdk.chains.common import get_fallback_private_key
99
from aleph.sdk.chains.ethereum import ETHAccount
10+
from aleph.sdk.chains.evm import EVMAccount
1011
from aleph.sdk.chains.remote import RemoteAccount
1112
from aleph.sdk.chains.solana import SOLAccount
13+
from aleph.sdk.chains.substrate import DOTAccount
1214
from aleph.sdk.conf import load_main_configuration, settings
1315
from aleph.sdk.evm_utils import get_chains_with_super_token
1416
from aleph.sdk.types import AccountFromPrivateKey
@@ -18,10 +20,24 @@
1820
T = TypeVar("T", bound=AccountFromPrivateKey)
1921

2022
chain_account_map: Dict[Chain, Type[T]] = { # type: ignore
21-
Chain.ETH: ETHAccount,
23+
Chain.ARBITRUM: EVMAccount,
2224
Chain.AVAX: ETHAccount,
2325
Chain.BASE: ETHAccount,
26+
Chain.BLAST: EVMAccount,
27+
Chain.BOB: EVMAccount,
28+
Chain.CYBER: EVMAccount,
29+
Chain.DOT: DOTAccount,
30+
Chain.ETH: ETHAccount,
31+
Chain.FRAXTAL: EVMAccount,
32+
Chain.LINEA: EVMAccount,
33+
Chain.LISK: EVMAccount,
34+
Chain.METIS: EVMAccount,
35+
Chain.MODE: EVMAccount,
36+
Chain.OPTIMISM: EVMAccount,
37+
Chain.POL: EVMAccount,
2438
Chain.SOL: SOLAccount,
39+
Chain.WORLDCHAIN: EVMAccount,
40+
Chain.ZORA: EVMAccount,
2541
}
2642

2743

@@ -43,7 +59,7 @@ def account_from_hex_string(
4359
return account_type(bytes.fromhex(private_key_str)) # type: ignore
4460

4561
account_type = load_chain_account_type(chain)
46-
account = account_type(bytes.fromhex(private_key_str))
62+
account = account_type(bytes.fromhex(private_key_str), chain)
4763
if chain in get_chains_with_super_token():
4864
account.switch_chain(chain)
4965
return account # type: ignore
@@ -62,7 +78,7 @@ def account_from_file(
6278
return account_type(private_key) # type: ignore
6379

6480
account_type = load_chain_account_type(chain)
65-
account = account_type(private_key)
81+
account = account_type(private_key, chain)
6682
if chain in get_chains_with_super_token():
6783
account.switch_chain(chain)
6884
return account
@@ -76,21 +92,29 @@ def _load_account(
7692
) -> AccountFromPrivateKey:
7793
"""Load an account from a private key string or file, or from the configuration file."""
7894

79-
# Loads configuration if no account_type is specified
80-
if not account_type:
81-
config = load_main_configuration(settings.CONFIG_FILE)
95+
config = load_main_configuration(settings.CONFIG_FILE)
96+
default_chain = settings.DEFAULT_CHAIN
97+
98+
if not chain:
8299
if config and hasattr(config, "chain"):
83-
account_type = load_chain_account_type(config.chain)
100+
chain = config.chain
84101
logger.debug(
85102
f"Detected {config.chain} account for path {settings.CONFIG_FILE}"
86103
)
87104
else:
88-
account_type = account_type = load_chain_account_type(
89-
Chain.ETH
90-
) # Defaults to ETHAccount
105+
chain = default_chain
91106
logger.warning(
92-
f"No main configuration data found in {settings.CONFIG_FILE}, defaulting to {account_type and account_type.__name__}"
107+
f"No main configuration found on path {settings.CONFIG_FILE}, defaulting to {chain}"
93108
)
109+
else:
110+
chain = default_chain
111+
112+
# Loads configuration if no account_type is specified
113+
if not account_type:
114+
account_type = load_chain_account_type(chain)
115+
logger.debug(
116+
f"No account type specified defaulting to {account_type and account_type.__name__}"
117+
)
94118

95119
# Loads private key from a string
96120
if private_key_str:

src/aleph/sdk/chains/evm.py

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from decimal import Decimal
2+
from pathlib import Path
3+
from typing import Awaitable, Optional
4+
5+
from aleph_message.models import Chain
6+
from eth_account import Account # type: ignore
7+
8+
from .common import get_fallback_private_key
9+
from .ethereum import ETHAccount
10+
11+
12+
class EVMAccount(ETHAccount):
13+
def __init__(self, private_key: bytes, chain: Optional[Chain] = None):
14+
super().__init__(private_key, chain)
15+
# Decide if we have to send also the specified chain value or always use ETH
16+
# if chain:
17+
# self.CHAIN = chain
18+
19+
@staticmethod
20+
def from_mnemonic(mnemonic: str, chain: Optional[Chain] = None) -> "EVMAccount":
21+
Account.enable_unaudited_hdwallet_features()
22+
return EVMAccount(
23+
private_key=Account.from_mnemonic(mnemonic=mnemonic).key, chain=chain
24+
)
25+
26+
def get_token_balance(self) -> Decimal:
27+
raise ValueError(f"Token not implemented for this chain {self.CHAIN}")
28+
29+
def get_super_token_balance(self) -> Decimal:
30+
raise ValueError(f"Super token not implemented for this chain {self.CHAIN}")
31+
32+
def create_flow(self, receiver: str, flow: Decimal) -> Awaitable[str]:
33+
raise ValueError(f"Flow creation not implemented for this chain {self.CHAIN}")
34+
35+
def get_flow(self, receiver: str):
36+
raise ValueError(f"Get flow not implemented for this chain {self.CHAIN}")
37+
38+
def update_flow(self, receiver: str, flow: Decimal) -> Awaitable[str]:
39+
raise ValueError(f"Flow update not implemented for this chain {self.CHAIN}")
40+
41+
def delete_flow(self, receiver: str) -> Awaitable[str]:
42+
raise ValueError(f"Flow deletion not implemented for this chain {self.CHAIN}")
43+
44+
45+
def get_fallback_account(
46+
path: Optional[Path] = None, chain: Optional[Chain] = None
47+
) -> ETHAccount:
48+
return ETHAccount(private_key=get_fallback_private_key(path=path), chain=chain)

src/aleph/sdk/conf.py

+58-4
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,9 @@ class Settings(BaseSettings):
100100
active=False,
101101
),
102102
# MAINNETS
103-
Chain.ETH: ChainInfo(
104-
chain_id=1,
105-
rpc="https://eth-mainnet.public.blastapi.io",
106-
token="0x27702a26126e0B3702af63Ee09aC4d1A084EF628",
103+
Chain.ARBITRUM: ChainInfo(
104+
chain_id=42161,
105+
rpc="https://arbitrum-one.publicnode.com",
107106
),
108107
Chain.AVAX: ChainInfo(
109108
chain_id=43114,
@@ -117,12 +116,65 @@ class Settings(BaseSettings):
117116
token="0xc0Fbc4967259786C743361a5885ef49380473dCF",
118117
super_token="0xc0Fbc4967259786C743361a5885ef49380473dCF",
119118
),
119+
Chain.BLAST: ChainInfo(
120+
chain_id=81457,
121+
rpc="https://blastl2-mainnet.public.blastapi.io",
122+
),
123+
Chain.BOB: ChainInfo(
124+
chain_id=60808,
125+
rpc="https://bob-mainnet.public.blastapi.io",
126+
),
120127
Chain.BSC: ChainInfo(
121128
chain_id=56,
122129
rpc="https://binance.llamarpc.com",
123130
token="0x82D2f8E02Afb160Dd5A480a617692e62de9038C4",
124131
active=False,
125132
),
133+
Chain.CYBER: ChainInfo(
134+
chain_id=7560,
135+
rpc="https://rpc.cyber.co",
136+
),
137+
Chain.ETH: ChainInfo(
138+
chain_id=1,
139+
rpc="https://eth-mainnet.public.blastapi.io",
140+
token="0x27702a26126e0B3702af63Ee09aC4d1A084EF628",
141+
),
142+
Chain.FRAXTAL: ChainInfo(
143+
chain_id=252,
144+
rpc="https://rpc.frax.com",
145+
),
146+
Chain.LINEA: ChainInfo(
147+
chain_id=59144,
148+
rpc="https://linea-rpc.publicnode.com",
149+
),
150+
Chain.LISK: ChainInfo(
151+
chain_id=1135,
152+
rpc="https://rpc.api.lisk.com",
153+
),
154+
Chain.METIS: ChainInfo(
155+
chain_id=1088,
156+
rpc="https://metis.drpc.org",
157+
),
158+
Chain.MODE: ChainInfo(
159+
chain_id=34443,
160+
rpc="https://mode.drpc.org",
161+
),
162+
Chain.OPTIMISM: ChainInfo(
163+
chain_id=10,
164+
rpc="https://optimism-rpc.publicnode.com",
165+
),
166+
Chain.POL: ChainInfo(
167+
chain_id=137,
168+
rpc="https://polygon.gateway.tenderly.co",
169+
),
170+
Chain.WORLDCHAIN: ChainInfo(
171+
chain_id=480,
172+
rpc="https://worldchain-mainnet.gateway.tenderly.co",
173+
),
174+
Chain.ZORA: ChainInfo(
175+
chain_id=7777777,
176+
rpc="https://rpc.zora.energy/",
177+
),
126178
}
127179
# Add all placeholders to allow easy dynamic setup of CHAINS
128180
CHAINS_SEPOLIA_ACTIVE: Optional[bool] = None
@@ -136,6 +188,8 @@ class Settings(BaseSettings):
136188
CHAINS_BASE_RPC: Optional[str] = None
137189
CHAINS_BSC_RPC: Optional[str] = None
138190

191+
DEFAULT_CHAIN: Chain = Chain.ETH
192+
139193
# Dns resolver
140194
DNS_IPFS_DOMAIN: ClassVar[str] = "ipfs.public.aleph.sh"
141195
DNS_PROGRAM_DOMAIN: ClassVar[str] = "program.public.aleph.sh"

src/aleph/sdk/evm_utils.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,16 @@ def get_super_token_address(
7979
return None
8080

8181

82-
def get_chains_with_holding() -> List[Union[Chain, str]]:
82+
def get_compatible_chains() -> List[Union[Chain, str]]:
8383
return [chain for chain, info in settings.CHAINS.items() if info.active]
8484

8585

86+
def get_chains_with_holding() -> List[Union[Chain, str]]:
87+
return [
88+
chain for chain, info in settings.CHAINS.items() if info.active and info.token
89+
]
90+
91+
8692
def get_chains_with_super_token() -> List[Union[Chain, str]]:
8793
return [
8894
chain

src/aleph/sdk/types.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
__all__ = ("StorageEnum", "Account", "AccountFromPrivateKey", "GenericMessage")
88

9-
from aleph_message.models import AlephMessage
9+
from aleph_message.models import AlephMessage, Chain
1010

1111

1212
class StorageEnum(str, Enum):
@@ -35,7 +35,7 @@ def get_public_key(self) -> str: ...
3535
class AccountFromPrivateKey(Account, Protocol):
3636
"""Only accounts that are initialized from a private key string are supported."""
3737

38-
def __init__(self, private_key: bytes): ...
38+
def __init__(self, private_key: bytes, chain: Chain): ...
3939

4040
async def sign_raw(self, buffer: bytes) -> bytes: ...
4141

@@ -77,6 +77,6 @@ class ChainInfo(BaseModel):
7777

7878
chain_id: int
7979
rpc: str
80-
token: str
80+
token: Optional[str] = None
8181
super_token: Optional[str] = None
8282
active: bool = True

0 commit comments

Comments
 (0)