Skip to content

Commit

Permalink
Merge pull request #555 from skalenetwork/skale-contracts
Browse files Browse the repository at this point in the history
Integrate skale-contracts library
  • Loading branch information
DimaStebaev authored Apr 16, 2024
2 parents 6cdac9f + 5683233 commit af18f01
Show file tree
Hide file tree
Showing 20 changed files with 150 additions and 144 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ jobs:
PIP_USERNAME: ${{ secrets.PIP_USERNAME }}
PIP_PASSWORD: ${{ secrets.PIP_PASSWORD }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
uses: actions/setup-python@v4
with:
cache: 'pip'
python-version: ${{ matrix.python-version }}
- name: Install host dependencies
run: |
Expand Down
20 changes: 11 additions & 9 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ jobs:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
MANAGER_TAG: "1.10.0-v1.10.0.0"
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
submodules: true
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
uses: actions/setup-python@v4
with:
cache: 'pip'
python-version: ${{ matrix.python-version }}

- name: Install python dependencies
Expand All @@ -30,7 +31,7 @@ jobs:
- name: Launch hardhat node
working-directory: hardhat-node
run: |
docker-compose up -d && sleep 20
docker-compose up -d && sleep 20
- name: Deploy manager
run: |
Expand All @@ -39,7 +40,7 @@ jobs:
- name: Show stats before tests
if: always()
run: |
run: |
sudo lsblk -f
sudo free -h
Expand All @@ -52,7 +53,7 @@ jobs:
- name: Show stats after tests
if: always()
run: |
run: |
sudo lsblk -f
sudo free -h
Expand All @@ -67,13 +68,14 @@ jobs:
MANAGER_TAG: "1.9.0-develop.20"
ALLOCATOR_TAG: "2.2.2-develop.0"
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
submodules: true

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
uses: actions/setup-python@v4
with:
cache: 'pip'
python-version: ${{ matrix.python-version }}

- name: Install host dependencies
Expand All @@ -85,7 +87,7 @@ jobs:
- name: Launch hardhat node
working-directory: hardhat-node
run: |
docker-compose up -d && sleep 20
docker-compose up -d && sleep 20
- name: Deploy manager contracts
run: |
Expand All @@ -103,6 +105,6 @@ jobs:
- name: Show stats after tests
if: always()
run: |
run: |
sudo lsblk -f
sudo free -h
5 changes: 3 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

setup(
name='skale.py',
version='6.2',
version='7',
description='SKALE client tools',
long_description_markdown_filename='README.md',
author='SKALE Labs',
Expand All @@ -43,8 +43,9 @@
install_requires=[
"asyncio==3.4.3",
"pyyaml==6.0",
"sgx.py==0.9dev2",
"redis==4.4.4",
"sgx.py==0.9dev2",
"skale-contracts==1.0.1a5",
"typing-extensions==4.9.0",
"web3==6.13.0"
],
Expand Down
8 changes: 3 additions & 5 deletions skale/contracts/allocator/escrow.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
def beneficiary_escrow(transaction):
@functools.wraps(transaction)
def wrapper(self, *args, beneficiary_address, **kwargs):
self.contract = self.init_beneficiary_contract(beneficiary_address)
self.contract = self.skale.instance.get_contract('Escrow', beneficiary_address)
return transaction(self, *args, **kwargs)
return wrapper

Expand All @@ -38,10 +38,8 @@ class Escrow(BaseContract):
def allocator(self):
return self.skale.allocator

def init_beneficiary_contract(self, beneficiary_address: str):
beneficiary_escrow_address = self.allocator.get_escrow_address(beneficiary_address)
return Escrow(self.skale, f'escrow_{beneficiary_address}', beneficiary_escrow_address,
self.contract.abi).contract
def init_contract(self, skale, address, abi) -> None:
self.contract = None

@beneficiary_escrow
@transaction_method
Expand Down
5 changes: 4 additions & 1 deletion skale/contracts/base_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,10 @@ def __init__(self, skale, name, address, abi):
self.skale = skale
self.name = name
self.address = Web3.to_checksum_address(address)
self.contract = skale.web3.eth.contract(address=self.address, abi=abi)
self.init_contract(skale, address, abi)

def init_contract(self, skale, address, abi) -> None:
self.contract = skale.web3.eth.contract(address=address, abi=abi)

def __getattr__(self, attr):
"""Fallback for contract calls"""
Expand Down
17 changes: 16 additions & 1 deletion skale/skale_allocator.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with SKALE.py. If not, see <https://www.gnu.org/licenses/>.
from __future__ import annotations

import logging
from typing import TYPE_CHECKING
from web3.constants import ADDRESS_ZERO

from skale.skale_base import SkaleBase
import skale.contracts.allocator as contracts
Expand All @@ -26,6 +29,9 @@
from skale.utils.contract_types import ContractTypes
from skale.utils.helper import get_contracts_info

if TYPE_CHECKING:
from eth_typing import ChecksumAddress


logger = logging.getLogger(__name__)

Expand All @@ -45,6 +51,15 @@ def spawn_skale_allocator_lib(skale):


class SkaleAllocator(SkaleBase):
"""Represents skale-allocator smart contracts"""
@property
def project_name(self) -> str:
return 'skale-allocator'

def get_contract_address(self, name) -> ChecksumAddress:
if name == 'Escrow':
return ADDRESS_ZERO
return super().get_contract_address(name)

def set_contracts_info(self):
self.init_contract_manager()
self._SkaleBase__contracts_info = get_contracts_info(CONTRACTS_INFO)
75 changes: 47 additions & 28 deletions skale/skale_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,23 @@
# You should have received a copy of the GNU Affero General Public License
# along with SKALE.py. If not, see <https://www.gnu.org/licenses/>.

from __future__ import annotations

import abc
import logging
from typing import TYPE_CHECKING

from skale_contracts import skale_contracts

from skale.wallets import BaseWallet
from skale.utils.abi_utils import get_contract_address_by_name, get_contract_abi_by_name
from skale.utils.exceptions import InvalidWalletError, EmptyWalletError
from skale.utils.web3_utils import default_gas_price, init_web3

from skale.utils.helper import get_abi
from skale.contracts.contract_manager import ContractManager

if TYPE_CHECKING:
from eth_typing import Address, ChecksumAddress


logger = logging.getLogger(__name__)

Expand All @@ -39,23 +45,30 @@ class EmptyPrivateKey(Exception):
class SkaleBase:
__metaclass__ = abc.ABCMeta

def __init__(self, endpoint, abi_filepath,
def __init__(self, endpoint, alias_or_address: str,
wallet=None, state_path=None,
ts_diff=None, provider_timeout=30):
logger.info(f'Initing skale.py, endpoint: {endpoint}, '
f'wallet: {type(wallet).__name__}')
self._abi_filepath = abi_filepath
logger.info('Initializing skale.py, endpoint: %s, wallet: %s',
endpoint, type(wallet).__name__)
self._endpoint = endpoint
self.web3 = init_web3(endpoint,
state_path=state_path,
ts_diff=ts_diff,
provider_timeout=provider_timeout)
self.network = skale_contracts.get_network_by_provider(self.web3.provider)
self.project = self.network.get_project(self.project_name)
self.instance = self.project.get_instance(alias_or_address)
self.__contracts = {}
self.__contracts_info = {}
self.set_contracts_info()
if wallet:
self.wallet = wallet

@property
@abc.abstractmethod
def project_name(self) -> str:
"""Name of smart contracts project"""

@property
def gas_price(self):
return default_gas_price(self.web3)
Expand All @@ -82,46 +95,52 @@ def set_contracts_info(self):
return

def init_contract_manager(self):
abi = get_abi(self._abi_filepath)
self.add_lib_contract('contract_manager', ContractManager, abi)
self.add_lib_contract('contract_manager', ContractManager, 'ContractManager')

def __init_contract_from_info(self, abi, contract_info):
def __init_contract_from_info(self, contract_info):
if contract_info.upgradeable:
self.init_upgradeable_contract(contract_info, abi)
self.init_upgradeable_contract(contract_info)
else:
self.add_lib_contract(contract_info.name, contract_info.contract_class,
abi)
self.add_lib_contract(
contract_info.name,
contract_info.contract_class,
contract_info.contract_name
)

def init_upgradeable_contract(self, contract_info, abi):
def init_upgradeable_contract(self, contract_info):
address = self.get_contract_address(contract_info.contract_name)
self.add_lib_contract(contract_info.name, contract_info.contract_class,
abi, address)

def add_lib_contract(self, name, contract_class,
abi, contract_address=None):
address = contract_address or get_contract_address_by_name(
abi, name)
logger.debug(f'Fetching abi for {name}, address {address}')
contract_abi = get_contract_abi_by_name(abi, name)
self.add_lib_contract(
contract_info.name,
contract_info.contract_class,
contract_info.contract_name,
address
)

def add_lib_contract(self, name: str, contract_class,
contract_name: str, contract_address: Address = None):
address = contract_address or self.instance.get_contract_address(contract_name)
logger.debug('Fetching abi for %s, address %s', name, address)
contract_abi = self.instance.abi[contract_name]
self.add_contract(name, contract_class(
self, name, address, contract_abi))

def add_contract(self, name, contract):
self.__contracts[name] = contract

def get_contract_address(self, name):
return self.contract_manager.get_contract_address(name)
def get_contract_address(self, name) -> ChecksumAddress:
return self.web3.to_checksum_address(
self.instance.get_contract_address(name)
)

def __get_contract_by_name(self, name):
return self.__contracts[name]

def __getattr__(self, name):
if name not in self.__contracts:
if not self.__contracts_info.get(name):
logger.warning(f'{name} method/contract wasn\'t found')
logger.warning("%s method/contract wasn't found", name)
return None
logger.debug(f'Contract {name} wasn\'t inited, creating now')
logger.debug("Contract %s wasn't inited, creating now", name)
contract_info = self.__contracts_info[name]
abi = get_abi(self._abi_filepath)
self.__init_contract_from_info(abi, contract_info)
self.__init_contract_from_info(contract_info)
return self.__get_contract_by_name(name)
21 changes: 8 additions & 13 deletions skale/skale_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from skale.contracts.contract_manager import ContractManager
from skale.utils.contract_info import ContractInfo
from skale.utils.contract_types import ContractTypes
from skale.utils.helper import get_abi, get_contracts_info
from skale.utils.helper import get_contracts_info


logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -60,21 +60,16 @@
ContractTypes.API, False),
ContractInfo('distributor', 'Distributor', contracts.Distributor,
ContractTypes.API, False),
ContractInfo('slashing_table', 'Distributor', contracts.SlashingTable,
ContractInfo('slashing_table', 'SlashingTable', contracts.SlashingTable,
ContractTypes.API, False),
ContractInfo('wallets', 'Wallets', contracts.Wallets,
ContractTypes.API, True),
ContractInfo('bounty_v2', 'Bounty', contracts.BountyV2,
ContractInfo('bounty_v2', 'BountyV2', contracts.BountyV2,
ContractTypes.API, True),
ContractInfo('punisher', 'Punisher', contracts.Punisher,
ContractTypes.API, True),
ContractInfo('sync_manager', 'SyncManager', contracts.SyncManager,
ContractTypes.API, False),
]


DEBUG_CONTRACTS_INFO = [

ContractInfo('time_helpers_with_debug', 'TimeHelpersWithDebug', contracts.TimeHelpersWithDebug,
ContractTypes.API, False)
]
Expand All @@ -86,11 +81,11 @@ def spawn_skale_manager_lib(skale):


class SkaleManager(SkaleBase):
"""Represents skale-manager smart contracts"""
@property
def project_name(self) -> str:
return 'skale-manager'

def set_contracts_info(self):
self.init_contract_manager()
abi = get_abi(self._abi_filepath)
self._SkaleBase__contracts_info = get_contracts_info(CONTRACTS_INFO)
if self._SkaleBase__is_debug_contracts(abi):
logger.info('Debug contracts found in ABI file')
self._SkaleBase__contracts_info.update(
get_contracts_info(DEBUG_CONTRACTS_INFO))
Loading

0 comments on commit af18f01

Please sign in to comment.