mirror of https://github.com/nucypher/nucypher.git
Remove batch deposits
parent
08e2098dc2
commit
b384911e5d
|
@ -36,7 +36,6 @@ For a guide of how to deploy these contracts automatically, see the :doc:`Deploy
|
|||
#. Approve tokens transfer to the ``StakingEscrow`` contract. These tokens are future staking rewards
|
||||
#. Run the ``initialize(uint256)`` method to initialize the ``StakingEscrow`` contract
|
||||
#. Approve tokens transfer for distribution to the ``WorkLock`` contract and call ``tokenDeposit(uint256)`` method
|
||||
#. Pre-deposit tokens to the ``StakingEscrow`` using ``batchDeposit(address[], uint256[], uint256[], uint16[])``
|
||||
|
||||
Alice's Contract Interaction
|
||||
----------------------------
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Deprecated StakingEscrow features to reduce code size: batch deposits, testContract flag, separate setters for related contracts.
|
|
@ -352,92 +352,6 @@ class ContractAdministrator(NucypherTokenActor):
|
|||
receipts = deployer.rollback()
|
||||
return receipts
|
||||
|
||||
def batch_deposits(self,
|
||||
allocation_data_filepath: str,
|
||||
interactive: bool = True,
|
||||
emitter: StdoutEmitter = None,
|
||||
gas_limit: int = None
|
||||
) -> Dict[str, dict]:
|
||||
"""
|
||||
The allocations file is a JSON or CSV file containing a list of substakes.
|
||||
Each substake is comprised of a staker address, an amount of tokens locked (in NuNits),
|
||||
and a lock duration (in periods).
|
||||
|
||||
It accepts both CSV and JSON formats. Example allocation file in CSV format:
|
||||
|
||||
"checksum_address","amount","lock_periods"
|
||||
"0xFABADA",123456,30
|
||||
"0xFABADA",789,45
|
||||
|
||||
Example allocation file in JSON format:
|
||||
|
||||
[ {"checksum_address": "0xFABADA", "amount": 123456, "lock_periods": 30},
|
||||
{"checksum_address": "0xFABADA", "amount": 789, "lock_periods": 45}]
|
||||
"""
|
||||
|
||||
if interactive and not emitter:
|
||||
raise ValueError("'emitter' is a required keyword argument when interactive is True.")
|
||||
|
||||
allocator = Allocator(allocation_data_filepath, self.registry, self.deployer_address)
|
||||
|
||||
# TODO: Check validity of input address (check TX)
|
||||
|
||||
if emitter:
|
||||
blockchain = BlockchainInterfaceFactory.get_interface()
|
||||
chain_name = blockchain.client.chain_name
|
||||
paint_input_allocation_file(emitter, allocator.allocations)
|
||||
|
||||
if interactive:
|
||||
click.confirm("Continue with the allocations process?", abort=True)
|
||||
|
||||
batch_deposit_receipts, failed = dict(), False
|
||||
with click.progressbar(length=len(allocator.allocations),
|
||||
label="Allocation progress",
|
||||
show_eta=False) as bar:
|
||||
|
||||
while allocator.pending_deposits and not failed:
|
||||
|
||||
self.activate_deployer(refresh=True)
|
||||
|
||||
try:
|
||||
deposited_stakers, receipt = allocator.deposit_next_batch(sender_address=self.deployer_address,
|
||||
gas_limit=gas_limit)
|
||||
except (TestTransactionFailed, ValidationError, ValueError): # TODO: 1950
|
||||
if emitter:
|
||||
emitter.echo(f"\nFailed to deploy next batch. These addresses weren't funded:", color="yellow")
|
||||
for staker in allocator.pending_deposits:
|
||||
emitter.echo(f"\t{staker}", color="yellow")
|
||||
emitter.echo(f"\nThe failure is caused by the following exception:")
|
||||
|
||||
for line in traceback.format_exception(*sys.exc_info()):
|
||||
emitter.echo(line, color='red')
|
||||
failed = True
|
||||
else:
|
||||
number_of_deposits = len(deposited_stakers)
|
||||
if emitter:
|
||||
emitter.echo(f"\nDeployed allocations for {number_of_deposits} stakers:")
|
||||
for staker in deposited_stakers:
|
||||
emitter.echo(f"\t{staker}")
|
||||
emitter.echo()
|
||||
bar._last_line = None
|
||||
bar.render_progress()
|
||||
|
||||
bar.update(number_of_deposits)
|
||||
|
||||
if emitter:
|
||||
emitter.echo()
|
||||
paint_receipt_summary(emitter=emitter,
|
||||
receipt=receipt,
|
||||
chain_name=chain_name, # TODO: this variable might be unused
|
||||
transaction_type=f'batch_deposit_{number_of_deposits}_stakers')
|
||||
|
||||
batch_deposit_receipts.update({staker: {'batch_deposit': receipt} for staker in deposited_stakers})
|
||||
|
||||
if interactive:
|
||||
click.pause(info=f"\nPress any key to continue with next batch of allocations")
|
||||
|
||||
return batch_deposit_receipts
|
||||
|
||||
def save_deployment_receipts(self, receipts: dict, filename_prefix: str = 'deployment') -> str:
|
||||
config_root = DEFAULT_CONFIG_ROOT # We force the use of the default here.
|
||||
filename = f'{filename_prefix}-receipts-{self.deployer_address[:6]}-{maya.now().epoch}.json'
|
||||
|
@ -472,142 +386,6 @@ class ContractAdministrator(NucypherTokenActor):
|
|||
return receipt
|
||||
|
||||
|
||||
class Allocator:
|
||||
class AllocationInputError(Exception):
|
||||
"""Raised when the allocation data file doesn't have the correct format"""
|
||||
|
||||
OCCUPATION_RATIO = 0.9 # When there's no explicit gas limit, we'll try to use the block limit up to this ratio
|
||||
|
||||
def __init__(self, filepath: str, registry, deployer_address):
|
||||
|
||||
self.log = Logger("allocator")
|
||||
self.staking_agent = ContractAgency.get_agent(StakingEscrowAgent,
|
||||
registry=registry) # type: StakingEscrowAgent
|
||||
self.max_substakes = self.staking_agent.contract.functions.MAX_SUB_STAKES().call()
|
||||
self.allocations = dict()
|
||||
self.deposited = set()
|
||||
self.economics = EconomicsFactory.get_economics(registry)
|
||||
|
||||
self.__total_to_allocate = 0
|
||||
self.__process_allocation_data(str(filepath))
|
||||
self.__approve_token_transfer(registry, deployer_address)
|
||||
|
||||
def __process_allocation_data(self, filepath: str):
|
||||
try:
|
||||
with open(filepath, 'r') as allocation_file:
|
||||
if filepath.endswith(".csv"):
|
||||
reader = csv.DictReader(allocation_file)
|
||||
allocation_data = list(reader)
|
||||
else: # Assume it's JSON by default
|
||||
allocation_data = json.load(allocation_file)
|
||||
except FileNotFoundError:
|
||||
raise self.AllocationInputError(f"No allocation data file found at {filepath}")
|
||||
|
||||
# Pre-process allocations data
|
||||
for entry in allocation_data:
|
||||
try:
|
||||
staker = to_checksum_address(entry['checksum_address'])
|
||||
amount = int(entry['amount'])
|
||||
lock_periods = int(entry['lock_periods'])
|
||||
except (KeyError, ValueError) as e:
|
||||
raise self.AllocationInputError(f"Invalid allocation data: {str(e)}")
|
||||
else:
|
||||
self._add_substake(staker, amount, lock_periods)
|
||||
self.__total_to_allocate += amount
|
||||
|
||||
def __approve_token_transfer(self, registry, deployer_address):
|
||||
token_agent = ContractAgency.get_agent(NucypherTokenAgent, registry=registry) # type: NucypherTokenAgent
|
||||
|
||||
balance = token_agent.get_balance(deployer_address)
|
||||
if balance < self.__total_to_allocate:
|
||||
raise ValueError(f"Not enough tokens to allocate."
|
||||
f"We need at least {NU.from_nunits(self.__total_to_allocate)}.")
|
||||
|
||||
allowance = token_agent.get_allowance(owner=deployer_address, spender=self.staking_agent.contract_address)
|
||||
if allowance < self.__total_to_allocate:
|
||||
self.log.debug(f"Allocating a total of {NU.from_nunits(self.__total_to_allocate)}")
|
||||
_allowance_receipt = token_agent.increase_allowance(sender_address=deployer_address,
|
||||
spender_address=self.staking_agent.contract_address,
|
||||
increase=NuNits(self.__total_to_allocate - allowance))
|
||||
|
||||
def _add_substake(self, staker, amount, lock_periods):
|
||||
try:
|
||||
substakes = self.allocations[staker]
|
||||
if len(substakes) >= self.max_substakes:
|
||||
raise ValueError(f"Number of sub-stakes, {len(substakes)}, must be ≤ {self.max_substakes}")
|
||||
except KeyError:
|
||||
if list(self.staking_agent.get_all_stakes(staker_address=staker)):
|
||||
raise ValueError(f"{staker} is already a staker. It cannot be included in a batch deposit")
|
||||
substakes = list()
|
||||
self.allocations[staker] = substakes
|
||||
|
||||
message = f"Invalid substake for {staker}: "
|
||||
if amount < self.economics.minimum_allowed_locked:
|
||||
message += f"Amount ({amount}) is below the min allowed ({self.economics.minimum_allowed_locked})"
|
||||
raise ValueError(message)
|
||||
overall_amount = sum([amount for amount, periods in substakes])
|
||||
if overall_amount + amount > self.economics.maximum_allowed_locked:
|
||||
message += f"Total amount is above the max allowed ({self.economics.maximum_allowed_locked})"
|
||||
raise ValueError(message)
|
||||
if lock_periods < self.economics.minimum_locked_periods:
|
||||
message += f"Lock periods ({lock_periods}) are below the min ({self.economics.minimum_locked_periods})"
|
||||
raise ValueError(message)
|
||||
|
||||
substakes.append((amount, lock_periods))
|
||||
|
||||
def deposit_next_batch(self,
|
||||
sender_address: str,
|
||||
gas_limit: int = None) -> Tuple[List[str], dict]:
|
||||
|
||||
pending_stakers = self.pending_deposits
|
||||
|
||||
self.log.debug(f"Constructing next batch. "
|
||||
f"Currently, {len(pending_stakers)} stakers pending, {len(self.deposited)} deposited.")
|
||||
|
||||
batch_size = 1
|
||||
if not gas_limit:
|
||||
block_limit = self.staking_agent.blockchain.client.w3.eth.getBlock('latest').gasLimit
|
||||
gas_limit = int(self.OCCUPATION_RATIO * block_limit)
|
||||
self.log.debug(f"Gas limit for this batch is {gas_limit}")
|
||||
|
||||
# Execute a dry-run of the batch deposit method, incrementing the batch size, until it's too big and fails.
|
||||
last_good_batch = None
|
||||
while batch_size <= len(pending_stakers):
|
||||
test_batch = {staker: self.allocations[staker] for staker in pending_stakers[:batch_size]}
|
||||
batch_parameters = self.staking_agent.construct_batch_deposit_parameters(deposits=test_batch)
|
||||
try:
|
||||
estimated_gas = self.staking_agent.batch_deposit(*batch_parameters,
|
||||
sender_address=sender_address,
|
||||
dry_run=True,
|
||||
gas_limit=gas_limit)
|
||||
except (TestTransactionFailed, ValidationError, ValueError): # TODO: 1950
|
||||
self.log.debug(f"Batch of {len(test_batch)} is too big. Let's stick to {len(test_batch) - 1} then")
|
||||
break
|
||||
else:
|
||||
self.log.debug(f"Batch of {len(test_batch)} stakers fits in single TX ({estimated_gas} gas). "
|
||||
f"Trying to squeeze one more staker...")
|
||||
last_good_batch = test_batch
|
||||
batch_size += 1
|
||||
|
||||
if not last_good_batch:
|
||||
message = "It was not possible to find a new batch of deposits. "
|
||||
raise ValueError(message)
|
||||
|
||||
batch_parameters = self.staking_agent.construct_batch_deposit_parameters(deposits=last_good_batch)
|
||||
receipt = self.staking_agent.batch_deposit(*batch_parameters,
|
||||
sender_address=sender_address,
|
||||
gas_limit=gas_limit)
|
||||
|
||||
deposited_stakers = list(last_good_batch.keys())
|
||||
self.deposited.update(deposited_stakers)
|
||||
return deposited_stakers, receipt
|
||||
|
||||
@property
|
||||
def pending_deposits(self) -> List[str]:
|
||||
pending_deposits = [staker for staker in self.allocations.keys() if staker not in self.deposited]
|
||||
return pending_deposits
|
||||
|
||||
|
||||
class MultiSigActor(BaseActor):
|
||||
class UnknownExecutive(Exception):
|
||||
"""
|
||||
|
|
|
@ -461,58 +461,6 @@ class StakingEscrowAgent(EthereumContractAgent):
|
|||
sender_address=staker_address)
|
||||
return receipt
|
||||
|
||||
@contract_api(CONTRACT_CALL)
|
||||
def construct_batch_deposit_parameters(self, deposits: Dict[ChecksumAddress, List[Tuple[int, int]]]) -> Tuple[list, list, list, list]:
|
||||
max_substakes: int = self.contract.functions.MAX_SUB_STAKES().call()
|
||||
stakers: List[ChecksumAddress] = list()
|
||||
number_of_substakes: List[int] = list()
|
||||
amounts: List[NuNits] = list()
|
||||
lock_periods: List[int] = list()
|
||||
for staker, substakes in deposits.items():
|
||||
if not 0 < len(substakes) <= max_substakes:
|
||||
raise self.RequirementError(f"Number of substakes for staker {staker} must be >0 and ≤{max_substakes}")
|
||||
# require(value >= minAllowableLockedTokens & & periods >= minLockedPeriods);
|
||||
# require(info.value <= maxAllowableLockedTokens);
|
||||
# require(info.subStakes.length == 0);
|
||||
stakers.append(staker)
|
||||
number_of_substakes.append(len(substakes))
|
||||
staker_amounts, staker_periods = zip(*substakes)
|
||||
amounts.extend(staker_amounts)
|
||||
lock_periods.extend(staker_periods)
|
||||
|
||||
return stakers, number_of_substakes, amounts, lock_periods
|
||||
|
||||
@contract_api(TRANSACTION)
|
||||
def batch_deposit(self,
|
||||
stakers: List[ChecksumAddress],
|
||||
number_of_substakes: List[int],
|
||||
amounts: List[NuNits],
|
||||
lock_periods: List[PeriodDelta],
|
||||
sender_address: ChecksumAddress,
|
||||
dry_run: bool = False,
|
||||
gas_limit: Optional[Wei] = None
|
||||
) -> Union[TxReceipt, Wei]:
|
||||
|
||||
min_gas_batch_deposit: Wei = Wei(250_000) # TODO: move elsewhere?
|
||||
if gas_limit and gas_limit < min_gas_batch_deposit:
|
||||
raise ValueError(f"{gas_limit} is not enough gas for any batch deposit")
|
||||
|
||||
contract_function: ContractFunction = self.contract.functions.batchDeposit(
|
||||
stakers, number_of_substakes, amounts, lock_periods)
|
||||
if dry_run:
|
||||
payload: TxParams = {'from': sender_address}
|
||||
if gas_limit:
|
||||
payload['gas'] = gas_limit
|
||||
estimated_gas: Wei = Wei(contract_function.estimateGas(payload)) # If TX is not correct, or there's not enough gas, this will fail.
|
||||
if gas_limit and estimated_gas > gas_limit:
|
||||
raise ValueError(f"Estimated gas for transaction exceeds gas limit {gas_limit}")
|
||||
return estimated_gas
|
||||
else:
|
||||
receipt = self.blockchain.send_transaction(contract_function=contract_function,
|
||||
sender_address=sender_address,
|
||||
transaction_gas_limit=gas_limit)
|
||||
return receipt
|
||||
|
||||
@contract_api(TRANSACTION)
|
||||
def divide_stake(self,
|
||||
staker_address: ChecksumAddress,
|
||||
|
|
|
@ -46,7 +46,7 @@ interface WorkLockInterface {
|
|||
* @title StakingEscrow
|
||||
* @notice Contract holds and locks stakers tokens.
|
||||
* Each staker that locks their tokens will receive some compensation
|
||||
* @dev |v5.5.1|
|
||||
* @dev |v5.6.1|
|
||||
*/
|
||||
contract StakingEscrow is Issuer, IERC900History {
|
||||
|
||||
|
@ -633,63 +633,6 @@ contract StakingEscrow is Issuer, IERC900History {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @notice Batch deposit. Allowed only initial deposit for each staker
|
||||
* @param _stakers Stakers
|
||||
* @param _numberOfSubStakes Number of sub-stakes which belong to staker in _values and _periods arrays
|
||||
* @param _values Amount of tokens to deposit for each staker
|
||||
* @param _periods Amount of periods during which tokens will be locked for each staker
|
||||
*/
|
||||
function batchDeposit(
|
||||
address[] calldata _stakers,
|
||||
uint256[] calldata _numberOfSubStakes,
|
||||
uint256[] calldata _values,
|
||||
uint16[] calldata _periods
|
||||
)
|
||||
external
|
||||
{
|
||||
uint256 subStakesLength = _values.length;
|
||||
require(_stakers.length != 0 &&
|
||||
_stakers.length == _numberOfSubStakes.length &&
|
||||
subStakesLength >= _stakers.length &&
|
||||
_periods.length == subStakesLength);
|
||||
uint16 previousPeriod = getCurrentPeriod() - 1;
|
||||
uint16 nextPeriod = previousPeriod + 2;
|
||||
uint256 sumValue = 0;
|
||||
|
||||
uint256 j = 0;
|
||||
for (uint256 i = 0; i < _stakers.length; i++) {
|
||||
address staker = _stakers[i];
|
||||
uint256 numberOfSubStakes = _numberOfSubStakes[i];
|
||||
uint256 endIndex = j + numberOfSubStakes;
|
||||
require(numberOfSubStakes > 0 && subStakesLength >= endIndex);
|
||||
StakerInfo storage info = stakerInfo[staker];
|
||||
require(info.subStakes.length == 0 && !info.flags.bitSet(SNAPSHOTS_DISABLED_INDEX));
|
||||
// A staker can't be a worker for another staker
|
||||
require(stakerFromWorker[staker] == address(0));
|
||||
stakers.push(staker);
|
||||
policyManager.register(staker, previousPeriod);
|
||||
|
||||
for (; j < endIndex; j++) {
|
||||
uint256 value = _values[j];
|
||||
uint16 periods = _periods[j];
|
||||
require(value >= minAllowableLockedTokens && periods >= minLockedPeriods);
|
||||
info.value = info.value.add(value);
|
||||
info.subStakes.push(SubStakeInfo(nextPeriod, 0, periods, uint128(value)));
|
||||
sumValue = sumValue.add(value);
|
||||
emit Deposited(staker, value, periods);
|
||||
emit Locked(staker, value, nextPeriod, periods);
|
||||
}
|
||||
require(info.value <= maxAllowableLockedTokens);
|
||||
info.history.addSnapshot(info.value);
|
||||
}
|
||||
require(j == subStakesLength);
|
||||
uint256 lastGlobalBalance = uint256(balanceHistory.lastValue());
|
||||
balanceHistory.addSnapshot(lastGlobalBalance + sumValue);
|
||||
token.safeTransferFrom(msg.sender, address(this), sumValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Implementation of the receiveApproval(address,uint256,address,bytes) method
|
||||
* (see NuCypherToken contract). Deposit all tokens that were approved to transfer
|
||||
|
|
|
@ -66,8 +66,6 @@ from nucypher.cli.literature import (
|
|||
SUCCESSFUL_REGISTRY_DOWNLOAD,
|
||||
SUCCESSFUL_RETARGET,
|
||||
SUCCESSFUL_RETARGET_TX_BUILT,
|
||||
SUCCESSFUL_SAVE_BATCH_DEPOSIT_RECEIPTS,
|
||||
SUCCESSFUL_SAVE_DEPLOY_RECEIPTS,
|
||||
SUCCESSFUL_SAVE_MULTISIG_TX_PROPOSAL,
|
||||
SUCCESSFUL_UPGRADE,
|
||||
UNKNOWN_CONTRACT_NAME,
|
||||
|
@ -542,26 +540,6 @@ def contracts(general_config, actor_options, mode, activate, gas, ignore_deploye
|
|||
# emitter.echo(SUCCESSFUL_SAVE_DEPLOY_RECEIPTS.format(receipts_filepath=receipts_filepath), color='blue', bold=True)
|
||||
|
||||
|
||||
@deploy.command()
|
||||
@group_general_config
|
||||
@group_actor_options
|
||||
@click.option('--allocation-infile', help="Input path for token allocation JSON file", type=EXISTING_READABLE_FILE)
|
||||
@option_gas
|
||||
def allocations(general_config, actor_options, allocation_infile, gas):
|
||||
"""Deposit stake allocations in batches"""
|
||||
emitter = general_config.emitter
|
||||
ADMINISTRATOR, _, deployer_interface, local_registry = actor_options.create_actor(emitter)
|
||||
if not allocation_infile:
|
||||
allocation_infile = click.prompt(PROMPT_FOR_ALLOCATION_DATA_FILEPATH)
|
||||
receipts = ADMINISTRATOR.batch_deposits(allocation_data_filepath=allocation_infile,
|
||||
emitter=emitter,
|
||||
gas_limit=gas,
|
||||
interactive=not actor_options.force)
|
||||
receipts_filepath = ADMINISTRATOR.save_deployment_receipts(receipts=receipts, filename_prefix='batch_deposits')
|
||||
if emitter:
|
||||
emitter.echo(SUCCESSFUL_SAVE_BATCH_DEPOSIT_RECEIPTS.format(receipts_filepath=receipts_filepath), color='blue', bold=True)
|
||||
|
||||
|
||||
@deploy.command("transfer-ownership")
|
||||
@group_general_config
|
||||
@group_actor_options
|
||||
|
|
|
@ -425,8 +425,6 @@ DISPLAY_SENDER_TOKEN_BALANCE_BEFORE_TRANSFER = "Deployer NU balance: {token_bala
|
|||
|
||||
PROMPT_FOR_ALLOCATION_DATA_FILEPATH = "Enter allocations data filepath"
|
||||
|
||||
SUCCESSFUL_SAVE_BATCH_DEPOSIT_RECEIPTS = "Saved batch deposits receipts to {receipts_filepath}"
|
||||
|
||||
SUCCESSFUL_SAVE_DEPLOY_RECEIPTS = "Saved deployment receipts to {receipts_filepath}"
|
||||
|
||||
SUCCESSFUL_REGISTRY_CREATION = 'Wrote to registry {registry_outfile}'
|
||||
|
|
|
@ -72,7 +72,5 @@ def test_rapid_deployment(token_economics, test_registry, tmpdir, get_random_che
|
|||
with open(filepath, 'w') as f:
|
||||
json.dump(allocation_data, f)
|
||||
|
||||
administrator.batch_deposits(allocation_data_filepath=str(filepath), interactive=False)
|
||||
|
||||
minimum, default, maximum = 10, 20, 30
|
||||
administrator.set_fee_rate_range(minimum, default, maximum)
|
||||
|
|
|
@ -452,59 +452,3 @@ def test_remove_unused_stake(agency, testerchain, test_registry):
|
|||
assert stakes[3] == original_stakes[3]
|
||||
assert staking_agent.get_locked_tokens(staker_account, 1) == next_locked_tokens
|
||||
assert staking_agent.get_locked_tokens(staker_account, 0) == current_locked_tokens
|
||||
|
||||
|
||||
def test_batch_deposit(testerchain,
|
||||
agency,
|
||||
token_economics,
|
||||
mock_transacting_power_activation,
|
||||
get_random_checksum_address):
|
||||
|
||||
token_agent, staking_agent, _policy_agent = agency
|
||||
|
||||
amount = token_economics.minimum_allowed_locked
|
||||
lock_periods = token_economics.minimum_locked_periods
|
||||
|
||||
stakers = [get_random_checksum_address() for _ in range(4)]
|
||||
|
||||
N = 5
|
||||
substakes = [(amount, lock_periods)] * N
|
||||
deposits = {staker: substakes for staker in stakers}
|
||||
|
||||
batch_parameters = staking_agent.construct_batch_deposit_parameters(deposits=deposits)
|
||||
|
||||
assert batch_parameters[0] == stakers
|
||||
assert batch_parameters[1] == [N] * len(stakers)
|
||||
assert batch_parameters[2] == [amount] * (N * len(stakers))
|
||||
assert batch_parameters[3] == [lock_periods] * (N * len(stakers))
|
||||
|
||||
mock_transacting_power_activation(account=testerchain.etherbase_account, password=INSECURE_DEVELOPMENT_PASSWORD)
|
||||
|
||||
tokens_in_batch = sum(batch_parameters[2])
|
||||
|
||||
_receipt = token_agent.approve_transfer(amount=tokens_in_batch,
|
||||
spender_address=staking_agent.contract_address,
|
||||
sender_address=testerchain.etherbase_account)
|
||||
|
||||
not_enough_gas = 800_000
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
staking_agent.batch_deposit(*batch_parameters,
|
||||
sender_address=testerchain.etherbase_account,
|
||||
dry_run=True,
|
||||
gas_limit=not_enough_gas)
|
||||
|
||||
staking_agent.batch_deposit(*batch_parameters,
|
||||
sender_address=testerchain.etherbase_account,
|
||||
dry_run=True)
|
||||
|
||||
staking_agent.batch_deposit(*batch_parameters,
|
||||
sender_address=testerchain.etherbase_account)
|
||||
|
||||
for staker in stakers:
|
||||
assert staking_agent.owned_tokens(staker_address=staker) == amount * N
|
||||
staker_substakes = list(staking_agent.get_all_stakes(staker_address=staker))
|
||||
assert N == len(staker_substakes)
|
||||
for substake in staker_substakes:
|
||||
first_period, last_period, locked_value = substake
|
||||
assert last_period == first_period + lock_periods - 1
|
||||
assert locked_value == amount
|
||||
|
|
|
@ -260,33 +260,6 @@ def test_manual_proxy_retargeting(monkeypatch, testerchain, click_runner, token_
|
|||
assert proxy_deployer.target_contract.address == untargeted_deployment.address
|
||||
|
||||
|
||||
def test_batch_deposits(click_runner,
|
||||
testerchain,
|
||||
agency_local_registry,
|
||||
mock_allocation_infile,
|
||||
token_economics):
|
||||
#
|
||||
# Main
|
||||
#
|
||||
|
||||
deploy_command = ('allocations',
|
||||
'--registry-infile', agency_local_registry.filepath,
|
||||
'--allocation-infile', mock_allocation_infile,
|
||||
'--network', TEMPORARY_DOMAIN,
|
||||
'--provider', TEST_PROVIDER_URI)
|
||||
|
||||
account_index = '0\n'
|
||||
user_input = account_index + YES_ENTER + YES_ENTER
|
||||
|
||||
result = click_runner.invoke(deploy,
|
||||
deploy_command,
|
||||
input=user_input,
|
||||
catch_exceptions=False)
|
||||
assert result.exit_code == 0, result.output
|
||||
for allocation_address in testerchain.unassigned_accounts:
|
||||
assert allocation_address in result.output
|
||||
|
||||
|
||||
def test_manual_deployment_of_idle_network(click_runner):
|
||||
|
||||
if os.path.exists(ALTERNATE_REGISTRY_FILEPATH_2):
|
||||
|
|
|
@ -294,56 +294,6 @@ def preallocation_escrow_2(testerchain, token, staking_interface, staking_interf
|
|||
return contract
|
||||
|
||||
|
||||
|
||||
def test_batch_deposit(testerchain, token_economics, token, escrow, multisig):
|
||||
creator, staker1, staker2, staker3, staker4, _alice1, _alice2, *contracts_owners =\
|
||||
testerchain.client.accounts
|
||||
contracts_owners = sorted(contracts_owners)
|
||||
|
||||
# Travel to the start of the next period to prevent problems with unexpected overflow first period
|
||||
testerchain.time_travel(hours=1)
|
||||
|
||||
# Staker gives Escrow rights to transfer
|
||||
tx = token.functions.approve(escrow.address, 10000).transact({'from': staker1})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Check that nothing is locked
|
||||
assert 0 == escrow.functions.getLockedTokens(staker1, 0).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(staker2, 0).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(staker3, 0).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(staker4, 0).call()
|
||||
|
||||
# Deposit tokens for 1 staker
|
||||
pytest.staker1_tokens = token_economics.minimum_allowed_locked
|
||||
staker1_tokens = pytest.staker1_tokens
|
||||
duration = token_economics.minimum_locked_periods
|
||||
current_period = escrow.functions.getCurrentPeriod().call()
|
||||
|
||||
tx = token.functions.transfer(multisig.address, staker1_tokens).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = token.functions.approve(escrow.address, staker1_tokens) \
|
||||
.buildTransaction({'from': multisig.address, 'gasPrice': 0})
|
||||
execute_multisig_transaction(testerchain, multisig, [contracts_owners[0], contracts_owners[1]], tx)
|
||||
tx = escrow.functions.batchDeposit([staker1], [1], [staker1_tokens], [duration])\
|
||||
.buildTransaction({'from': multisig.address, 'gasPrice': 0})
|
||||
execute_multisig_transaction(testerchain, multisig, [contracts_owners[0], contracts_owners[1]], tx)
|
||||
|
||||
pytest.escrow_supply = token_economics.minimum_allowed_locked
|
||||
assert token.functions.balanceOf(escrow.address).call() == pytest.escrow_supply
|
||||
assert escrow.functions.getAllTokens(staker1).call() == staker1_tokens
|
||||
assert escrow.functions.getLockedTokens(staker1, 0).call() == 0
|
||||
assert escrow.functions.getLockedTokens(staker1, 1).call() == staker1_tokens
|
||||
assert escrow.functions.getLockedTokens(staker1, duration).call() == staker1_tokens
|
||||
assert escrow.functions.getLockedTokens(staker1, duration + 1).call() == 0
|
||||
|
||||
# Can't deposit tokens again for the same staker
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
execute_multisig_transaction(testerchain, multisig, [contracts_owners[0], contracts_owners[1]], tx)
|
||||
|
||||
tx = token.functions.approve(escrow.address, 0).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
|
||||
def test_staking_before_initialization(testerchain,
|
||||
token_economics,
|
||||
token,
|
||||
|
@ -356,11 +306,40 @@ def test_staking_before_initialization(testerchain,
|
|||
testerchain.client.accounts
|
||||
contracts_owners = sorted(contracts_owners)
|
||||
|
||||
# Travel to the start of the next period to prevent problems with unexpected overflow first period
|
||||
testerchain.time_travel(hours=1)
|
||||
|
||||
# Give staker some coins
|
||||
tx = token.functions.transfer(staker1, 10000).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert 10000 == token.functions.balanceOf(staker1).call()
|
||||
|
||||
# Check that nothing is locked
|
||||
assert 0 == escrow.functions.getLockedTokens(staker1, 0).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(staker2, 0).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(staker3, 0).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(staker4, 0).call()
|
||||
|
||||
# Deposit tokens for 1 staker
|
||||
tx = token.functions.approve(escrow.address, 10000).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
pytest.staker1_tokens = token_economics.minimum_allowed_locked
|
||||
staker1_tokens = pytest.staker1_tokens
|
||||
duration = token_economics.minimum_locked_periods
|
||||
tx = escrow.functions.deposit(staker1, staker1_tokens, duration).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
pytest.escrow_supply = token_economics.minimum_allowed_locked
|
||||
assert token.functions.balanceOf(escrow.address).call() == pytest.escrow_supply
|
||||
assert escrow.functions.getAllTokens(staker1).call() == staker1_tokens
|
||||
assert escrow.functions.getLockedTokens(staker1, 0).call() == 0
|
||||
assert escrow.functions.getLockedTokens(staker1, 1).call() == staker1_tokens
|
||||
assert escrow.functions.getLockedTokens(staker1, duration).call() == staker1_tokens
|
||||
assert escrow.functions.getLockedTokens(staker1, duration + 1).call() == 0
|
||||
|
||||
tx = token.functions.approve(escrow.address, 0).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Set and lock re-stake parameter in first preallocation escrow
|
||||
_wind_down, re_stake, _measure_work, _snapshots = escrow.functions.getFlags(preallocation_escrow_1.address).call()
|
||||
assert re_stake
|
||||
|
@ -652,6 +631,8 @@ def test_staking_after_worklock(testerchain,
|
|||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Staker transfers some tokens to the escrow and lock them
|
||||
tx = token.functions.approve(escrow.address, 1000).transact({'from': staker1})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = escrow.functions.deposit(staker1, 1000, 10).transact({'from': staker1})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = escrow.functions.bondWorker(staker1).transact({'from': staker1})
|
||||
|
|
|
@ -1256,302 +1256,6 @@ def test_allowable_locked_tokens(testerchain, token_economics, token, escrow_con
|
|||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
|
||||
def test_batch_deposit(testerchain, token, escrow_contract, deploy_contract):
|
||||
escrow = escrow_contract(1500, disable_reward=True)
|
||||
policy_manager_interface = testerchain.get_contract_factory('PolicyManagerForStakingEscrowMock')
|
||||
policy_manager = testerchain.client.get_contract(
|
||||
abi=policy_manager_interface.abi,
|
||||
address=escrow.functions.policyManager().call(),
|
||||
ContractFactoryClass=Contract)
|
||||
|
||||
creator = testerchain.client.accounts[0]
|
||||
deposit_log = escrow.events.Deposited.createFilter(fromBlock='latest')
|
||||
lock_log = escrow.events.Locked.createFilter(fromBlock='latest')
|
||||
|
||||
# Grant access to transfer tokens
|
||||
tx = token.functions.approve(escrow.address, 10000).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Can't deposit tokens if taking snapshots was disabled
|
||||
staker = testerchain.client.accounts[1]
|
||||
tx = escrow.functions.setSnapshots(False).transact({'from': staker})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = escrow.functions.batchDeposit([staker], [1], [1000], [10]).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Deposit tokens for 1 staker
|
||||
tx = escrow.functions.setSnapshots(True).transact({'from': staker})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = escrow.functions.batchDeposit([staker], [1], [1000], [10]).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
escrow_balance = 1000
|
||||
assert token.functions.balanceOf(escrow.address).call() == escrow_balance
|
||||
assert escrow.functions.getAllTokens(staker).call() == 1000
|
||||
assert escrow.functions.getLockedTokens(staker, 0).call() == 0
|
||||
assert escrow.functions.getLockedTokens(staker, 1).call() == 1000
|
||||
assert escrow.functions.getLockedTokens(staker, 10).call() == 1000
|
||||
assert escrow.functions.getLockedTokens(staker, 11).call() == 0
|
||||
current_period = escrow.functions.getCurrentPeriod().call()
|
||||
assert policy_manager.functions.getPeriodsLength(staker).call() == 1
|
||||
assert policy_manager.functions.getPeriod(staker, 0).call() == current_period - 1
|
||||
assert escrow.functions.getPastDowntimeLength(staker).call() == 0
|
||||
assert escrow.functions.getLastCommittedPeriod(staker).call() == 0
|
||||
|
||||
deposit_events = deposit_log.get_all_entries()
|
||||
assert len(deposit_events) == 1
|
||||
event_args = deposit_events[-1]['args']
|
||||
assert event_args['staker'] == staker
|
||||
assert event_args['value'] == 1000
|
||||
assert event_args['periods'] == 10
|
||||
|
||||
lock_events = lock_log.get_all_entries()
|
||||
assert len(lock_events) == 1
|
||||
event_args = lock_events[-1]['args']
|
||||
assert event_args['staker'] == staker
|
||||
assert event_args['value'] == 1000
|
||||
assert event_args['firstPeriod'] == current_period + 1
|
||||
assert event_args['periods'] == 10
|
||||
|
||||
# Can't deposit tokens again for the same staker twice
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = escrow.functions.batchDeposit([staker], [1], [1000], [10])\
|
||||
.transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Can't deposit tokens with too low or too high value
|
||||
staker = testerchain.client.accounts[2]
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = escrow.functions.batchDeposit([staker], [1], [1], [10])\
|
||||
.transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = escrow.functions.batchDeposit([staker], [1], [1501], [10])\
|
||||
.transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = escrow.functions.batchDeposit([staker], [1], [500], [1])\
|
||||
.transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = escrow.functions.batchDeposit([staker], [2], [1000, 501], [10, 10])\
|
||||
.transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Inconsistent input
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = escrow.functions.batchDeposit([staker], [0], [500], [10])\
|
||||
.transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = escrow.functions.batchDeposit([staker], [2], [500], [10])\
|
||||
.transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = escrow.functions.batchDeposit([staker], [1, 1], [500], [10])\
|
||||
.transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = escrow.functions.batchDeposit([staker], [1, 1], [500, 500], [10])\
|
||||
.transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = escrow.functions.batchDeposit([staker], [1, 1], [500, 500], [10, 10])\
|
||||
.transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
stakers = testerchain.client.accounts[2:4]
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = escrow.functions.batchDeposit(stakers, [1, 1], [500, 500, 500], [10, 10, 10])\
|
||||
.transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Initialize Escrow contract
|
||||
tx = escrow.functions.initialize(0, creator).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Deposit tokens for multiple stakers
|
||||
tx = token.functions.transfer(staker, 1500).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = token.functions.approve(escrow.address, 1500).transact({'from': staker})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
stakers = testerchain.client.accounts[2:7]
|
||||
tx = escrow.functions.setWindDown(True).transact({'from': stakers[0]})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
current_period = escrow.functions.getCurrentPeriod().call()
|
||||
tx = escrow.functions.batchDeposit(
|
||||
stakers, [1, 1, 1, 1, 1], [100, 200, 300, 400, 500], [50, 100, 150, 200, 250]
|
||||
).transact({'from': staker})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
escrow_balance += 1500
|
||||
assert token.functions.balanceOf(escrow.address).call() == escrow_balance
|
||||
deposit_events = deposit_log.get_all_entries()
|
||||
lock_events = lock_log.get_all_entries()
|
||||
|
||||
assert len(deposit_events) == 6
|
||||
assert len(lock_events) == 6
|
||||
|
||||
for index, staker in enumerate(stakers):
|
||||
value = 100 * (index + 1)
|
||||
duration = 50 * (index + 1)
|
||||
assert escrow.functions.getAllTokens(staker).call() == value
|
||||
assert escrow.functions.getLockedTokens(staker, 0).call() == 0
|
||||
assert escrow.functions.getLockedTokens(staker, 1).call() == value
|
||||
assert escrow.functions.getLockedTokens(staker, duration).call() == value
|
||||
assert escrow.functions.getLockedTokens(staker, duration + 1).call() == 0
|
||||
assert policy_manager.functions.getPeriodsLength(staker).call() == 1
|
||||
assert policy_manager.functions.getPeriod(staker, 0).call() == current_period - 1
|
||||
assert escrow.functions.getPastDowntimeLength(staker).call() == 0
|
||||
assert escrow.functions.getLastCommittedPeriod(staker).call() == 0
|
||||
|
||||
event_args = deposit_events[index + 1]['args']
|
||||
assert event_args['staker'] == staker
|
||||
assert event_args['value'] == value
|
||||
assert event_args['periods'] == duration
|
||||
|
||||
event_args = lock_events[index + 1]['args']
|
||||
assert event_args['staker'] == staker
|
||||
assert event_args['value'] == value
|
||||
assert event_args['firstPeriod'] == current_period + 1
|
||||
assert event_args['periods'] == duration
|
||||
|
||||
# Deposit tokens for multiple stakers with multiple sub-stakes
|
||||
stakers = testerchain.client.accounts[7:10]
|
||||
current_period = escrow.functions.getCurrentPeriod().call()
|
||||
|
||||
tx = escrow.functions.batchDeposit(
|
||||
stakers, [1, 2, 3], [100, 200, 300, 400, 500, 600], [50, 100, 150, 200, 250, 300])\
|
||||
.transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
escrow_balance += 2100
|
||||
assert token.functions.balanceOf(escrow.address).call() == escrow_balance
|
||||
deposit_events = deposit_log.get_all_entries()
|
||||
lock_events = lock_log.get_all_entries()
|
||||
|
||||
assert len(deposit_events) == 12
|
||||
assert len(lock_events) == 12
|
||||
|
||||
staker = stakers[0]
|
||||
duration = 50
|
||||
value = 100
|
||||
assert escrow.functions.getAllTokens(staker).call() == value
|
||||
assert escrow.functions.getLockedTokens(staker, 1).call() == value
|
||||
assert escrow.functions.getLockedTokens(staker, duration).call() == value
|
||||
assert escrow.functions.getLockedTokens(staker, duration + 1).call() == 0
|
||||
assert policy_manager.functions.getPeriodsLength(staker).call() == 1
|
||||
assert policy_manager.functions.getPeriod(staker, 0).call() == current_period - 1
|
||||
assert escrow.functions.getPastDowntimeLength(staker).call() == 0
|
||||
assert escrow.functions.getLastCommittedPeriod(staker).call() == 0
|
||||
assert escrow.functions.getSubStakesLength(staker).call() == 1
|
||||
|
||||
event_args = deposit_events[6]['args']
|
||||
assert event_args['staker'] == staker
|
||||
assert event_args['value'] == value
|
||||
assert event_args['periods'] == duration
|
||||
|
||||
event_args = lock_events[6]['args']
|
||||
assert event_args['staker'] == staker
|
||||
assert event_args['value'] == value
|
||||
assert event_args['firstPeriod'] == current_period + 1
|
||||
assert event_args['periods'] == duration
|
||||
|
||||
staker = stakers[1]
|
||||
duration1 = 100
|
||||
duration2 = 150
|
||||
value1 = 200
|
||||
value2 = 300
|
||||
assert escrow.functions.getAllTokens(staker).call() == value1 + value2
|
||||
assert escrow.functions.getLockedTokens(staker, 0).call() == 0
|
||||
assert escrow.functions.getLockedTokens(staker, 1).call() == value1 + value2
|
||||
assert escrow.functions.getLockedTokens(staker, duration1).call() == value1 + value2
|
||||
assert escrow.functions.getLockedTokens(staker, duration1 + 1).call() == value2
|
||||
assert escrow.functions.getLockedTokens(staker, duration2).call() == value2
|
||||
assert escrow.functions.getLockedTokens(staker, duration2 + 1).call() == 0
|
||||
assert policy_manager.functions.getPeriodsLength(staker).call() == 1
|
||||
assert policy_manager.functions.getPeriod(staker, 0).call() == current_period - 1
|
||||
assert escrow.functions.getPastDowntimeLength(staker).call() == 0
|
||||
assert escrow.functions.getLastCommittedPeriod(staker).call() == 0
|
||||
assert escrow.functions.getSubStakesLength(staker).call() == 2
|
||||
|
||||
event_args = deposit_events[7]['args']
|
||||
assert event_args['staker'] == staker
|
||||
assert event_args['value'] == value1
|
||||
assert event_args['periods'] == duration1
|
||||
|
||||
event_args = lock_events[7]['args']
|
||||
assert event_args['staker'] == staker
|
||||
assert event_args['value'] == value1
|
||||
assert event_args['firstPeriod'] == current_period + 1
|
||||
assert event_args['periods'] == duration1
|
||||
|
||||
event_args = deposit_events[8]['args']
|
||||
assert event_args['staker'] == staker
|
||||
assert event_args['value'] == value2
|
||||
assert event_args['periods'] == duration2
|
||||
|
||||
event_args = lock_events[8]['args']
|
||||
assert event_args['staker'] == staker
|
||||
assert event_args['value'] == value2
|
||||
assert event_args['firstPeriod'] == current_period + 1
|
||||
assert event_args['periods'] == duration2
|
||||
|
||||
staker = stakers[2]
|
||||
duration1 = 200
|
||||
duration2 = 250
|
||||
duration3 = 300
|
||||
value1 = 400
|
||||
value2 = 500
|
||||
value3 = 600
|
||||
assert escrow.functions.getAllTokens(staker).call() == value1 + value2 + value3
|
||||
assert escrow.functions.getLockedTokens(staker, 0).call() == 0
|
||||
assert escrow.functions.getLockedTokens(staker, 1).call() == value1 + value2 + value3
|
||||
assert escrow.functions.getLockedTokens(staker, duration1).call() == value1 + value2 + value3
|
||||
assert escrow.functions.getLockedTokens(staker, duration1 + 1).call() == value2 + value3
|
||||
assert escrow.functions.getLockedTokens(staker, duration2).call() == value2 + value3
|
||||
assert escrow.functions.getLockedTokens(staker, duration2 + 1).call() == value3
|
||||
assert escrow.functions.getLockedTokens(staker, duration3).call() == value3
|
||||
assert escrow.functions.getLockedTokens(staker, duration3 + 1).call() == 0
|
||||
assert policy_manager.functions.getPeriodsLength(staker).call() == 1
|
||||
assert policy_manager.functions.getPeriod(staker, 0).call() == current_period - 1
|
||||
assert escrow.functions.getPastDowntimeLength(staker).call() == 0
|
||||
assert escrow.functions.getLastCommittedPeriod(staker).call() == 0
|
||||
assert escrow.functions.getSubStakesLength(staker).call() == 3
|
||||
|
||||
event_args = deposit_events[9]['args']
|
||||
assert event_args['staker'] == staker
|
||||
assert event_args['value'] == value1
|
||||
assert event_args['periods'] == duration1
|
||||
|
||||
event_args = lock_events[9]['args']
|
||||
assert event_args['staker'] == staker
|
||||
assert event_args['value'] == value1
|
||||
assert event_args['firstPeriod'] == current_period + 1
|
||||
assert event_args['periods'] == duration1
|
||||
|
||||
event_args = deposit_events[10]['args']
|
||||
assert event_args['staker'] == staker
|
||||
assert event_args['value'] == value2
|
||||
assert event_args['periods'] == duration2
|
||||
|
||||
event_args = lock_events[10]['args']
|
||||
assert event_args['staker'] == staker
|
||||
assert event_args['value'] == value2
|
||||
assert event_args['firstPeriod'] == current_period + 1
|
||||
assert event_args['periods'] == duration2
|
||||
|
||||
event_args = deposit_events[11]['args']
|
||||
assert event_args['staker'] == staker
|
||||
assert event_args['value'] == value3
|
||||
assert event_args['periods'] == duration3
|
||||
|
||||
event_args = lock_events[11]['args']
|
||||
assert event_args['staker'] == staker
|
||||
assert event_args['value'] == value3
|
||||
assert event_args['firstPeriod'] == current_period + 1
|
||||
assert event_args['periods'] == duration3
|
||||
|
||||
|
||||
def test_staking_from_worklock(testerchain, token, escrow_contract, token_economics, deploy_contract):
|
||||
"""
|
||||
Tests for staking method: depositFromWorkLock
|
||||
|
|
|
@ -183,6 +183,7 @@ def estimate_gas(analyzer: AnalyzeGas = None) -> None:
|
|||
compiled_contract = testerchain._raw_contract_cache[contract_name]
|
||||
|
||||
version = list(compiled_contract).pop()
|
||||
# FIXME this value includes constructor code size but should not
|
||||
bin_runtime = compiled_contract[version]['evm']['bytecode']['object']
|
||||
bin_length_in_bytes = len(bin_runtime) // 2
|
||||
percentage = int(100 * bin_length_in_bytes / MAX_SIZE)
|
||||
|
@ -224,6 +225,11 @@ def estimate_gas(analyzer: AnalyzeGas = None) -> None:
|
|||
tx = function.transact(transaction)
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# First deposit ever is the most expensive, make it to remove unusual gas spending
|
||||
transact(token_functions.approve(staking_agent.contract_address, MIN_ALLOWED_LOCKED * 10), {'from': origin})
|
||||
transact(staker_functions.deposit(everyone_else[0], MIN_ALLOWED_LOCKED, MIN_LOCKED_PERIODS), {'from': origin})
|
||||
testerchain.time_travel(periods=1)
|
||||
|
||||
#
|
||||
# Give Ursula and Alice some coins
|
||||
#
|
||||
|
@ -240,34 +246,6 @@ def estimate_gas(analyzer: AnalyzeGas = None) -> None:
|
|||
transact(token_functions.approve(staking_agent.contract_address, MIN_ALLOWED_LOCKED * 6), {'from': staker2})
|
||||
transact(token_functions.approve(staking_agent.contract_address, MIN_ALLOWED_LOCKED * 6), {'from': staker3})
|
||||
|
||||
#
|
||||
# Batch deposit tokens
|
||||
#
|
||||
current_period = staking_agent.get_current_period()
|
||||
transact(token_functions.approve(staking_agent.contract_address, MIN_ALLOWED_LOCKED * 10), {'from': origin})
|
||||
transact_and_log("Batch deposit tokens for 5 owners x 2 sub-stakes",
|
||||
staker_functions.batchDeposit(everyone_else[0:5],
|
||||
[2] * 5,
|
||||
[MIN_ALLOWED_LOCKED] * 10,
|
||||
[MIN_LOCKED_PERIODS] * 10),
|
||||
{'from': origin})
|
||||
|
||||
transact(token_functions.approve(staking_agent.contract_address, MIN_ALLOWED_LOCKED * 24), {'from': origin})
|
||||
transact_and_log("Batch deposit tokens for 1 owners x 24 sub-stakes",
|
||||
staker_functions.batchDeposit([everyone_else[6]],
|
||||
[24],
|
||||
[MIN_ALLOWED_LOCKED] * 24,
|
||||
[MIN_LOCKED_PERIODS] * 24),
|
||||
{'from': origin})
|
||||
|
||||
transact(token_functions.approve(staking_agent.contract_address, MIN_ALLOWED_LOCKED * 24 * 5), {'from': origin})
|
||||
transact_and_log("Batch deposit tokens for 5 owners x 24 sub-stakes",
|
||||
staker_functions.batchDeposit(everyone_else[7:12],
|
||||
[24]*5,
|
||||
[MIN_ALLOWED_LOCKED] * (24 * 5),
|
||||
[MIN_LOCKED_PERIODS] * (24 * 5)),
|
||||
{'from': origin})
|
||||
|
||||
#
|
||||
# Ursula and Alice transfer some tokens to the escrow and lock them
|
||||
#
|
||||
|
@ -587,13 +565,12 @@ def estimate_gas(analyzer: AnalyzeGas = None) -> None:
|
|||
|
||||
# Large number of sub-stakes
|
||||
number_of_sub_stakes = 24
|
||||
transact(token_functions.approve(staking_agent.contract_address, 0), {'from': origin})
|
||||
transact(token_functions.approve(staking_agent.contract_address, MIN_ALLOWED_LOCKED * number_of_sub_stakes),
|
||||
{'from': origin})
|
||||
transact(staker_functions.batchDeposit([staker4],
|
||||
[number_of_sub_stakes],
|
||||
[MIN_ALLOWED_LOCKED] * number_of_sub_stakes,
|
||||
[MIN_LOCKED_PERIODS] * number_of_sub_stakes),
|
||||
{'from': origin})
|
||||
for i in range(number_of_sub_stakes):
|
||||
transact(staker_functions.deposit(staker4, MIN_ALLOWED_LOCKED, MIN_LOCKED_PERIODS),
|
||||
{'from': origin})
|
||||
transact(staker_functions.bondWorker(staker4), {'from': staker4})
|
||||
transact(staker_functions.setWindDown(True), {'from': staker4})
|
||||
|
||||
|
|
Loading…
Reference in New Issue