Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MEX-581] tests claim on behalf #60

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ __pycache__
/deploy/*/upgrader_outputs
/dump
/abis
/wasm
/wasm
*downloads
*state_dump
2 changes: 2 additions & 0 deletions config.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
ESCROW_BYTECODE_PATH = DEFAULT_WORKSPACE.absolute() / "wasm-v3" / "lkmex-transfer.wasm"
LK_WRAP_BYTECODE_PATH = DEFAULT_WORKSPACE.absolute() / "wasm-v3" / "locked-token-wrapper.wasm"
COMPOSABLE_TASKS_BYTECODE_PATH = "https://github.com/multiversx/mx-exchange-tools-sc/releases/download/v1.0.0-rc3/composable-tasks.wasm"
PERMISSIONS_HUBS_BYTECODE_PATH = DEFAULT_WORKSPACE.home() / "projects" / "dex" / "dex-v2" / "sc-dex-rs" / "output-docker" / "permissions-hub" / "permissions-hub.wasm"


# ------------ Generic configuration below; Modify only in case of framework changes ------------ #
Expand Down Expand Up @@ -113,6 +114,7 @@
ESCROWS = "escrows"
LK_WRAPS = "lk_wraps"
COMPOSABLE_TASKS = "composable_tasks"
PERMISSIONS_HUBS = "permissions_hubs"


def get_default_tokens_file():
Expand Down
45 changes: 45 additions & 0 deletions contracts/farm_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,27 @@ def enterFarm(self, network_provider: NetworkProviders, user: Account, event: En

return multi_esdt_endpoint_call(function_purpose, network_provider.proxy, gas_limit, user,
Address(self.address), enterFarmFn, sc_args)

def enter_farm_on_behalf(self, network_provider: NetworkProviders, user: Account, event: EnterFarmEvent) -> str:
function_purpose = "enter farm on behalf"
logger.info(function_purpose)
logger.debug(f"Account: {user.address}")

enterFarmFn = "enterFarmOnBehalf"

logger.info(f"Calling {enterFarmFn} endpoint...")

gas_limit = 50000000

tokens = [ESDTToken(event.farming_tk, event.farming_tk_nonce, event.farming_tk_amount)]
if event.farm_tk:
tokens.append(ESDTToken(event.farm_tk, event.farm_tk_nonce, event.farm_tk_amount))

sc_args = [tokens,
Address(event.on_behalf)]

return multi_esdt_endpoint_call(function_purpose, network_provider.proxy, gas_limit, user,
Address(self.address), enterFarmFn, sc_args)

def exitFarm(self, network_provider: NetworkProviders, user: Account, event: ExitFarmEvent) -> str:
function_purpose = f"exit farm"
Expand Down Expand Up @@ -124,6 +145,19 @@ def claim_boosted_rewards(self, network_provider: NetworkProviders, user: Accoun

sc_args = [Address(event.user)] if event.user else []
return endpoint_call(network_provider.proxy, gas_limit, user, Address(self.address), claim_fn, sc_args)

def claim_rewards_on_behalf(self, network_provider: NetworkProviders, user: Account, event: ClaimRewardsFarmEvent) -> str:
function_purpose = f"claimRewardsOnBehalf"
logger.info(function_purpose)
logger.debug(f"Account: {user.address}")

gas_limit = 50000000
tokens = [ESDTToken(self.farmToken, event.nonce, event.amount)]
sc_args = [
tokens
]
return multi_esdt_endpoint_call(function_purpose, network_provider.proxy, gas_limit, user,
Address(self.address), "claimRewardsOnBehalf", sc_args)


def compoundRewards(self, network_provider: NetworkProviders, user: Account, event: CompoundRewardsFarmEvent) -> str:
Expand Down Expand Up @@ -385,6 +419,17 @@ def update_owner_or_admin(self, deployer: Account, proxy: ProxyNetworkProvider,
logger.debug(f"Arguments: {sc_args}")
return endpoint_call(proxy, gas_limit, deployer, Address(self.address), "updateOwnerOrAdmin", sc_args)

def set_permissions_hub_address(self, deployer: Account, proxy: ProxyNetworkProvider, address: str):
"""Only V3.
"""
function_purpose = "Set permissions hub address"
logger.info(function_purpose)

gas_limit = 10000000
sc_args = [address]
logger.debug(f"Arguments: {sc_args}")
return endpoint_call(proxy, gas_limit, deployer, Address(self.address), "setPermissionsHubAddress", sc_args)

def set_transfer_role_farm_token(self, deployer: Account, proxy: ProxyNetworkProvider, whitelisted_sc_address: str):
"""Only V2Boosted.
"""
Expand Down
124 changes: 124 additions & 0 deletions contracts/permissions_hub_contract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
from contracts.contract_identities import DEXContractInterface
from utils.contract_data_fetchers import PermissionsHubContractDataFetcher
from utils.logger import get_logger
from utils.utils_tx import endpoint_call, deploy
from utils.utils_chain import log_explorer_transaction
from utils.utils_generic import log_step_fail, log_step_pass, log_unexpected_args
from utils.utils_chain import Account, WrapperAddress as Address
from multiversx_sdk import CodeMetadata, ProxyNetworkProvider


logger = get_logger(__name__)


class PermissionsHubContract(DEXContractInterface):
def __init__(self, address: str = ""):
self.address = address

def get_config_dict(self) -> dict:
output_dict = {
"address": self.address
}
return output_dict

@classmethod
def load_config_dict(cls, config_dict: dict):
return PermissionsHubContract(address=config_dict['address'])

@classmethod
def load_contract_by_address(cls, address: str):
return PermissionsHubContract(address)

def contract_deploy(self, deployer: Account, proxy: ProxyNetworkProvider, bytecode_path, args: list):
"""Expecting as args:
"""
function_purpose = f"Deploy permissions hub contract"
logger.info(function_purpose)

metadata = CodeMetadata(upgradeable=True, payable_by_contract=True, readable=True)
gas_limit = 200000000

arguments = args
tx_hash, address = deploy(type(self).__name__, proxy, gas_limit, deployer, bytecode_path, metadata, arguments)
return tx_hash, address

def add_to_whitelist(self, deployer: Account, proxy: ProxyNetworkProvider, args: list) -> str:
"""Expecting as args:
- whitelisted_sc_addresses: list[address]
"""
function_purpose = "Add addresses to whitelist"
logger.info(function_purpose)

if len(args) < 1:
log_unexpected_args(function_purpose, args)
return ""

gas_limit = 30000000
sc_args = args
logger.debug(f"Arguments: {sc_args}")
return endpoint_call(proxy, gas_limit, deployer, Address(self.address), "whitelist", sc_args)

def remove_from_whitelist(self, deployer: Account, proxy: ProxyNetworkProvider, args: list) -> str:
"""Expecting as args:
- whitelisted_sc_addresses: list[address]
"""
function_purpose = "Remove addresses to whitelist"
logger.info(function_purpose)

if len(args) < 1:
log_unexpected_args(function_purpose, args)
return ""

gas_limit = 30000000
sc_args = args
logger.debug(f"Arguments: {sc_args}")
return endpoint_call(proxy, gas_limit, deployer, Address(self.address), "removeWhitelist", sc_args)

def add_to_blacklist(self, deployer: Account, proxy: ProxyNetworkProvider, args: list) -> str:
"""Expecting as args:
- blacklisted_sc_addresses: list[address]
"""
function_purpose = "Add addresses to blacklist"
logger.info(function_purpose)

if len(args) < 1:
log_unexpected_args(function_purpose, args)
return ""

gas_limit = 30000000
sc_args = args
logger.debug(f"Arguments: {sc_args}")
return endpoint_call(proxy, gas_limit, deployer, Address(self.address), "blacklist", sc_args)

def remove_from_blacklist(self, deployer: Account, proxy: ProxyNetworkProvider, args: list) -> str:
"""Expecting as args:
- blacklisted_sc_addresses: list[address]
"""
function_purpose = "Remove addresses from blacklist"
logger.info(function_purpose)

if len(args) < 1:
log_unexpected_args(function_purpose, args)
return ""

gas_limit = 30000000
sc_args = args
logger.debug(f"Arguments: {sc_args}")
return endpoint_call(proxy, gas_limit, deployer, Address(self.address), "removeBlacklist", sc_args)

def is_whitelisted(self, user: str, address: str, proxy: ProxyNetworkProvider) -> bool:
data_fetcher = PermissionsHubContractDataFetcher(Address(self.address), proxy.url)
raw_results = data_fetcher.get_data('isWhitelisted',
[
Address(address).get_public_key(),
Address(user).get_public_key()
])
if not raw_results:
return False
return bool(raw_results)

def contract_start(self, deployer: Account, proxy: ProxyNetworkProvider, args: list = None):
pass

def print_contract_info(self):
log_step_pass(f"Deployed permissions hub contract: {self.address}")
6 changes: 6 additions & 0 deletions deploy/configs-devnet/deploy_structure.json
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,12 @@
}
],

"permissions_hubs": [
{
"empty": 0
}
],

"farms_community": [

],
Expand Down
8 changes: 4 additions & 4 deletions deploy/configs-devnet/deployed_farms_boosted.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[
{
"farmingToken": "EGLDMEX-95c6d5",
"farmToken": "EGLDMEXFL-f0bc2e",
"farmToken": "EGLDMEXFL-2ed783",
"farmedToken": "MEX-a659d0",
"address": "erd1qqqqqqqqqqqqqpgq3chrzjdg3gu40zt6kes6w62cyz8tes6k0n4ssk3hj4",
"address": "erd1qqqqqqqqqqqqqpgqqjpfmappkpzq6kdju3mkqepk3d2kcymu0n4srd45sa",
"version": 4
},
{
Expand Down Expand Up @@ -50,9 +50,9 @@
},
{
"farmingToken": "HTMWEGLD-acd22a",
"farmToken": "HTMWEGLDFL-a7b3cc",
"farmToken": "HTMWEGLDFL-f9ec2b",
"farmedToken": "MEX-a659d0",
"address": "erd1qqqqqqqqqqqqqpgq0qrv3nqsfv5sg936anqu2a56x99jt4370n4sp55uny",
"address": "erd1qqqqqqqqqqqqqpgqrrghrmzzq3vczqpx2quaza4yyke5fudh0n4sxdhv67",
"version": 4
},
{
Expand Down
5 changes: 5 additions & 0 deletions deploy/configs-devnet/deployed_permissions_hubs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[
{
"address": "erd1qqqqqqqqqqqqqpgqwrntspndf3lqth9tgl9k4cde8prq3q4q0n4svee8fh"
}
]
24 changes: 24 additions & 0 deletions deploy/dex_structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from contracts.dex_proxy_contract import DexProxyContract
from contracts.governance_contract import GovernanceContract
from contracts.composable_tasks_contract import ComposableTasksContract
from contracts.permissions_hub_contract import PermissionsHubContract
from utils.utils_tx import NetworkProviders
from utils.utils_chain import hex_to_string
from utils.utils_chain import Account, WrapperAddress as Address
Expand Down Expand Up @@ -144,6 +145,7 @@ def add_clean_contract_deploy_arguments(cls, parser: ArgumentParser):
parser.add_argument("--escrows", action="store_true", help="Deploy clean escrows")
parser.add_argument("--lk-wraps", action="store_true", help="Deploy clean lk token wrappers")
parser.add_argument("--composable-tasks", action="store_true", help="Deploy clean composable tasks")
parser.add_argument("--permissions-hubs", action="store_true", help="Deploy clean permissions hubs")


class DeployStructure:
Expand Down Expand Up @@ -193,6 +195,9 @@ def __init__(self):
config.PAIRS_VIEW:
ContractStructure(config.PAIRS_VIEW, PairContract, config.PAIR_VIEW_BYTECODE_PATH,
self.pool_view_deploy, False),
config.PERMISSIONS_HUBS:
ContractStructure(config.PERMISSIONS_HUBS, PermissionsHubContract, config.PERMISSIONS_HUBS_BYTECODE_PATH,
self.permissions_hub_deploy, False),
config.FARMS_COMMUNITY:
ContractStructure(config.FARMS_COMMUNITY, FarmContract, config.FARM_COMMUNITY_BYTECODE_PATH,
self.farm_community_deploy, False),
Expand Down Expand Up @@ -1081,6 +1086,25 @@ def pool_view_deploy(self, contracts_index: str, deployer_account: Account, netw
deployed_contracts.append(dummy_pair_contract)
self.contracts[contracts_index].deployed_contracts = deployed_contracts

def permissions_hub_deploy(self, contracts_index: str, deployer_account: Account, network_providers: NetworkProviders):
contract_structure = self.contracts[contracts_index]
deployed_contracts = []
for _ in contract_structure.deploy_structure_list:
# deploy permissions hub contract
deployed_contract = PermissionsHubContract()
tx_hash, contract_address = deployed_contract.contract_deploy(deployer_account,
network_providers.proxy,
contract_structure.bytecode, [])
# check for deployment success and save the deployed address
if not network_providers.check_deploy_tx_status(tx_hash, contract_address, "permissions hub"):
return

deployed_contract.address = contract_address
log_step_pass(f"Permissions hub contract address: {contract_address}")

deployed_contracts.append(deployed_contract)
self.contracts[contracts_index].deployed_contracts = deployed_contracts

def farm_deploy(self, contracts_index: str, deployer_account: Account, network_providers: NetworkProviders):
contract_structure = self.contracts[contracts_index]
deployed_contracts = []
Expand Down
6 changes: 4 additions & 2 deletions events/farm_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

class EnterFarmEvent:
def __init__(self,
farming_token: str, farming_nonce: int, farming_amount,
farm_token: str, farm_nonce: int, farm_amount):
farming_token: str, farming_nonce: int, farming_amount: int,
farm_token: str, farm_nonce: int, farm_amount: int,
on_behalf: str = ""):
self.farming_tk = farming_token
self.farming_tk_nonce = farming_nonce
self.farming_tk_amount = farming_amount
self.farm_tk = farm_token
self.farm_tk_nonce = farm_nonce
self.farm_tk_amount = farm_amount
self.on_behalf = on_behalf # address of the user on behalf of whom the operation is executed


class ExitFarmEvent:
Expand Down
23 changes: 16 additions & 7 deletions tools/chain_simulator_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from utils.utils_chain import decode_merged_attributes, string_to_hex, dec_to_padded_hex
from utils.utils_chain import WrapperAddress, Account
from utils.utils_generic import log_step_fail, log_step_pass, log_warning
from tools.runners.account_state_runner import get_account_keys_online
from tools.runners.account_state_runner import get_account_keys_online, get_account_data_online
from multiversx_sdk import ProxyNetworkProvider


Expand Down Expand Up @@ -49,7 +49,7 @@ def get_contract_retrieval_labels(contracts: str) -> List[str]:
return contracts.split(",")


def fetch_states(context: Context, args) -> json:
def fetch_contract_states(context: Context, args) -> json:
proxy = ProxyNetworkProvider(args.gateway)
contracts_shard = WrapperAddress(context.get_contracts(config.ROUTER)[0].address).get_shard()
all_keys = list[dict]
Expand All @@ -67,15 +67,24 @@ def fetch_states(context: Context, args) -> json:
index = int(args.contract_index)
if index >= len(contracts):
log_step_fail(f"Contract index {index} is out of bounds for {label} contracts.")
return
return []
contracts = [contracts[index]]

# retrieve state for each contract
# retrieve keys and data for each contract
for i, contract in enumerate(contracts):
file = f"{STATES_FOLDER}/{block_number}_{label}_{i}_state.json"
keys = get_account_keys_online(contract.address, proxy.url, block_number, file)
all_keys.append(keys)
keys_file = f"{STATES_FOLDER}/{block_number}_{label}_{i}_state.json"
data_file = f"{STATES_FOLDER}/{block_number}_{label}_{i}_data.json"
keys = get_account_keys_online(contract.address, proxy.url, block_number, keys_file)
data = get_account_data_online(contract.address, proxy.url, block_number, data_file)

account_state = {}
account_state.update(data)
account_state['keys'] = keys

all_keys.append(account_state)

return all_keys

# get system account state - done later since it's gigantic
file = f"{STATES_FOLDER}/{block_number}_system_account_state.json"
if args.system_account == "offline":
Expand Down
Loading