mirror of https://github.com/nucypher/nucypher.git
commit
6269ad8619
|
@ -182,7 +182,8 @@ class ContractAdministrator(NucypherTokenActor):
|
|||
registry: BaseContractRegistry,
|
||||
deployer_address: str = None,
|
||||
client_password: str = None,
|
||||
economics: TokenEconomics = None):
|
||||
economics: TokenEconomics = None,
|
||||
staking_escrow_test_mode: bool = False):
|
||||
"""
|
||||
Note: super() is not called here to avoid setting the token agent.
|
||||
TODO: Review this logic ^^ "bare mode". #1510
|
||||
|
@ -199,6 +200,7 @@ class ContractAdministrator(NucypherTokenActor):
|
|||
|
||||
self.transacting_power = TransactingPower(password=client_password, account=deployer_address, cache=True)
|
||||
self.transacting_power.activate()
|
||||
self.staking_escrow_test_mode = staking_escrow_test_mode
|
||||
|
||||
def __repr__(self):
|
||||
r = '{name} - {deployer_address})'.format(name=self.__class__.__name__, deployer_address=self.deployer_address)
|
||||
|
@ -235,6 +237,9 @@ class ContractAdministrator(NucypherTokenActor):
|
|||
) -> Tuple[dict, BaseContractDeployer]:
|
||||
|
||||
Deployer = self.__get_deployer(contract_name=contract_name)
|
||||
if Deployer is StakingEscrowDeployer:
|
||||
kwargs.update({"test_mode": self.staking_escrow_test_mode})
|
||||
|
||||
deployer = Deployer(registry=self.registry,
|
||||
deployer_address=self.deployer_address,
|
||||
economics=self.economics,
|
||||
|
|
|
@ -483,16 +483,17 @@ class StakingEscrowDeployer(BaseContractDeployer, UpgradeableContractMixin, Owna
|
|||
|
||||
agency = StakingEscrowAgent
|
||||
contract_name = agency.registry_contract_name
|
||||
deployment_steps = ('contract_deployment', 'dispatcher_deployment', 'reward_transfer', 'initialize')
|
||||
deployment_steps = ('contract_deployment', 'dispatcher_deployment', 'approve_reward_transfer', 'initialize')
|
||||
_proxy_deployer = DispatcherDeployer
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
def __init__(self, test_mode: bool = False, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.__dispatcher_contract = None
|
||||
|
||||
token_contract_name = NucypherTokenDeployer.contract_name
|
||||
self.token_contract = self.blockchain.get_contract_by_name(registry=self.registry,
|
||||
contract_name=token_contract_name)
|
||||
self.test_mode = test_mode
|
||||
|
||||
def __check_policy_manager(self):
|
||||
result = self.contract.functions.policyManager().call()
|
||||
|
@ -509,7 +510,8 @@ class StakingEscrowDeployer(BaseContractDeployer, UpgradeableContractMixin, Owna
|
|||
"_minLockedPeriods": args[4],
|
||||
"_minAllowableLockedTokens": args[5],
|
||||
"_maxAllowableLockedTokens": args[6],
|
||||
"_minWorkerPeriods": args[7]
|
||||
"_minWorkerPeriods": args[7],
|
||||
"_isTestContract": self.test_mode
|
||||
}
|
||||
constructor_kwargs.update(overrides)
|
||||
constructor_kwargs = {k: v for k, v in constructor_kwargs.items() if v is not None}
|
||||
|
@ -597,19 +599,19 @@ class StakingEscrowDeployer(BaseContractDeployer, UpgradeableContractMixin, Owna
|
|||
# Switch the contract for the wrapped one
|
||||
the_escrow_contract = wrapped_escrow_contract
|
||||
|
||||
# 3 - Transfer the reward supply tokens to StakingEscrow #
|
||||
reward_function = self.token_contract.functions.transfer(the_escrow_contract.address,
|
||||
self.economics.erc20_reward_supply)
|
||||
# 3 - Approve transfer the reward supply tokens to StakingEscrow #
|
||||
approve_reward_function = self.token_contract.functions.approve(the_escrow_contract.address,
|
||||
self.economics.erc20_reward_supply)
|
||||
|
||||
# TODO: Confirmations / Successful Transaction Indicator / Events ?? - #1193, #1194
|
||||
reward_receipt = self.blockchain.send_transaction(contract_function=reward_function,
|
||||
sender_address=self.deployer_address,
|
||||
payload=origin_args)
|
||||
approve_reward_receipt = self.blockchain.send_transaction(contract_function=approve_reward_function,
|
||||
sender_address=self.deployer_address,
|
||||
payload=origin_args)
|
||||
if progress:
|
||||
progress.update(1)
|
||||
|
||||
# 4 - Initialize the StakingEscrow contract
|
||||
init_function = the_escrow_contract.functions.initialize()
|
||||
init_function = the_escrow_contract.functions.initialize(self.economics.erc20_reward_supply)
|
||||
|
||||
init_receipt = self.blockchain.send_transaction(contract_function=init_function,
|
||||
sender_address=self.deployer_address,
|
||||
|
@ -618,7 +620,7 @@ class StakingEscrowDeployer(BaseContractDeployer, UpgradeableContractMixin, Owna
|
|||
progress.update(1)
|
||||
|
||||
# Gather the transaction receipts
|
||||
ordered_receipts = (deploy_receipt, dispatcher_deploy_receipt, reward_receipt, init_receipt)
|
||||
ordered_receipts = (deploy_receipt, dispatcher_deploy_receipt, approve_reward_receipt, init_receipt)
|
||||
deployment_receipts = dict(zip(self.deployment_steps, ordered_receipts))
|
||||
|
||||
# Set the contract and transaction receipts #
|
||||
|
|
|
@ -238,6 +238,7 @@ class BaseContractRegistry(ABC):
|
|||
def id(self) -> str:
|
||||
"""Returns a hexstr of the registry contents."""
|
||||
blake = hashlib.blake2b()
|
||||
blake.update(self.__class__.__name__.encode())
|
||||
blake.update(json.dumps(self.read()).encode())
|
||||
digest = blake.digest().hex()
|
||||
return digest
|
||||
|
|
|
@ -6,6 +6,7 @@ import "zeppelin/math/SafeMath.sol";
|
|||
import "zeppelin/math/Math.sol";
|
||||
import "contracts/proxy/Upgradeable.sol";
|
||||
import "contracts/lib/AdditionalMath.sol";
|
||||
import "zeppelin/token/ERC20/SafeERC20.sol";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -13,9 +14,11 @@ import "contracts/lib/AdditionalMath.sol";
|
|||
* @dev |v1.1.2|
|
||||
*/
|
||||
contract Issuer is Upgradeable {
|
||||
using SafeERC20 for NuCypherToken;
|
||||
using SafeMath for uint256;
|
||||
using AdditionalMath for uint32;
|
||||
|
||||
event Burnt(address indexed sender, uint256 value);
|
||||
/// Issuer is initialized with a reserved reward
|
||||
event Initialized(uint256 reservedReward);
|
||||
|
||||
|
@ -97,14 +100,14 @@ contract Issuer is Upgradeable {
|
|||
/**
|
||||
* @notice Initialize reserved tokens for reward
|
||||
*/
|
||||
function initialize() public onlyOwner {
|
||||
function initialize(uint256 _reservedReward) public onlyOwner {
|
||||
require(currentSupply1 == 0);
|
||||
token.safeTransferFrom(msg.sender, address(this), _reservedReward);
|
||||
currentMintingPeriod = getCurrentPeriod();
|
||||
uint256 reservedReward = token.balanceOf(address(this));
|
||||
uint256 currentTotalSupply = totalSupply - reservedReward;
|
||||
uint256 currentTotalSupply = totalSupply - _reservedReward;
|
||||
currentSupply1 = currentTotalSupply;
|
||||
currentSupply2 = currentTotalSupply;
|
||||
emit Initialized(reservedReward);
|
||||
emit Initialized(_reservedReward);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -169,6 +172,16 @@ contract Issuer is Upgradeable {
|
|||
currentSupply2 = currentSupply2 - _amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Burn sender's tokens. Amount of tokens will be returned for future minting
|
||||
* @param _value Amount to burn
|
||||
*/
|
||||
function burn(uint256 _value) public {
|
||||
token.safeTransferFrom(msg.sender, address(this), _value);
|
||||
unMint(_value);
|
||||
emit Burnt(msg.sender, _value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns the number of tokens that can be mined
|
||||
*/
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
pragma solidity ^0.5.3;
|
||||
|
||||
|
||||
import "zeppelin/token/ERC20/SafeERC20.sol";
|
||||
import "contracts/Issuer.sol";
|
||||
|
||||
|
||||
|
@ -34,10 +33,9 @@ contract WorkLockInterface {
|
|||
/**
|
||||
* @notice Contract holds and locks stakers tokens.
|
||||
* Each staker that locks their tokens will receive some compensation
|
||||
* @dev |v1.4.1|
|
||||
* @dev |v1.5.1|
|
||||
*/
|
||||
contract StakingEscrow is Issuer {
|
||||
using SafeERC20 for NuCypherToken;
|
||||
using AdditionalMath for uint256;
|
||||
using AdditionalMath for uint16;
|
||||
|
||||
|
@ -118,6 +116,7 @@ contract StakingEscrow is Issuer {
|
|||
PolicyManagerInterface public policyManager;
|
||||
AdjudicatorInterface public adjudicator;
|
||||
WorkLockInterface public workLock;
|
||||
bool public isTestContract;
|
||||
|
||||
/**
|
||||
* @notice Constructor sets address of token contract and coefficients for mining
|
||||
|
@ -130,6 +129,7 @@ contract StakingEscrow is Issuer {
|
|||
* @param _minAllowableLockedTokens Min amount of tokens that can be locked
|
||||
* @param _maxAllowableLockedTokens Max amount of tokens that can be locked
|
||||
* @param _minWorkerPeriods Min amount of periods while a worker can't be changed
|
||||
* @param _isTestContract True if contract is only for tests
|
||||
*/
|
||||
constructor(
|
||||
NuCypherToken _token,
|
||||
|
@ -140,7 +140,8 @@ contract StakingEscrow is Issuer {
|
|||
uint16 _minLockedPeriods,
|
||||
uint256 _minAllowableLockedTokens,
|
||||
uint256 _maxAllowableLockedTokens,
|
||||
uint16 _minWorkerPeriods
|
||||
uint16 _minWorkerPeriods,
|
||||
bool _isTestContract
|
||||
)
|
||||
public
|
||||
Issuer(
|
||||
|
@ -157,6 +158,7 @@ contract StakingEscrow is Issuer {
|
|||
minAllowableLockedTokens = _minAllowableLockedTokens;
|
||||
maxAllowableLockedTokens = _maxAllowableLockedTokens;
|
||||
minWorkerPeriods = _minWorkerPeriods;
|
||||
isTestContract = _isTestContract;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -196,7 +198,7 @@ contract StakingEscrow is Issuer {
|
|||
*/
|
||||
function setWorkLock(WorkLockInterface _workLock) external onlyOwner {
|
||||
// WorkLock can be set only once
|
||||
require(address(workLock) == address(0));
|
||||
require(address(workLock) == address(0) || isTestContract);
|
||||
// This escrow must be the escrow for the new worklock
|
||||
require(_workLock.escrow() == address(this));
|
||||
workLock = _workLock;
|
||||
|
@ -1213,6 +1215,7 @@ contract StakingEscrow is Issuer {
|
|||
/// @dev the `onlyWhileUpgrading` modifier works through a call to the parent `verifyState`
|
||||
function verifyState(address _testTarget) public {
|
||||
super.verifyState(_testTarget);
|
||||
require((delegateGet(_testTarget, "isTestContract()") == 0) == !isTestContract);
|
||||
require(uint16(delegateGet(_testTarget, "minWorkerPeriods()")) == minWorkerPeriods);
|
||||
require(delegateGet(_testTarget, "minAllowableLockedTokens()") == minAllowableLockedTokens);
|
||||
require(delegateGet(_testTarget, "maxAllowableLockedTokens()") == maxAllowableLockedTokens);
|
||||
|
@ -1277,6 +1280,7 @@ contract StakingEscrow is Issuer {
|
|||
minAllowableLockedTokens = escrow.minAllowableLockedTokens();
|
||||
maxAllowableLockedTokens = escrow.maxAllowableLockedTokens();
|
||||
minWorkerPeriods = escrow.minWorkerPeriods();
|
||||
isTestContract = escrow.isTestContract();
|
||||
|
||||
// Create fake period
|
||||
lockedPerPeriod[RESERVED_PERIOD] = 111;
|
||||
|
|
|
@ -2,148 +2,245 @@ pragma solidity ^0.5.3;
|
|||
|
||||
|
||||
import "zeppelin/math/SafeMath.sol";
|
||||
import "zeppelin/token/ERC20/SafeERC20.sol";
|
||||
import "zeppelin/utils/Address.sol";
|
||||
import "contracts/NuCypherToken.sol";
|
||||
import "contracts/StakingEscrow.sol";
|
||||
import "contracts/staking_contracts/PreallocationEscrow.sol";
|
||||
import "contracts/staking_contracts/AbstractStakingContract.sol";
|
||||
import "contracts/lib/AdditionalMath.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @notice The WorkLock distribution contract
|
||||
*/
|
||||
contract WorkLock {
|
||||
using SafeERC20 for NuCypherToken;
|
||||
using SafeMath for uint256;
|
||||
using AdditionalMath for uint256;
|
||||
using Address for address payable;
|
||||
using Address for address;
|
||||
|
||||
event Bid(address indexed staker, uint256 depositedETH, uint256 claimedTokens);
|
||||
event Claimed(address indexed staker, uint256 claimedTokens);
|
||||
event Refund(address indexed staker, uint256 refundETH, uint256 completedWork);
|
||||
event Deposited(address indexed sender, uint256 value);
|
||||
event Bid(address indexed sender, uint256 depositedETH);
|
||||
event Claimed(address indexed sender, address preallocationEscrow, uint256 claimedTokens);
|
||||
event Refund(address indexed sender, address preallocationEscrow, uint256 refundETH, uint256 completedWork);
|
||||
event Burnt(address indexed sender, uint256 value);
|
||||
event Canceled(address indexed sender, uint256 value);
|
||||
|
||||
struct WorkInfo {
|
||||
uint256 depositedETH;
|
||||
uint256 completedWork;
|
||||
bool claimed;
|
||||
PreallocationEscrow preallocationEscrow;
|
||||
}
|
||||
|
||||
NuCypherToken public token;
|
||||
StakingEscrow public escrow;
|
||||
StakingInterfaceRouter public router;
|
||||
|
||||
uint256 public startBidDate;
|
||||
uint256 public endBidDate;
|
||||
// ETH -> NU
|
||||
uint256 public depositRate;
|
||||
// Work (reward in NU) -> ETH
|
||||
uint256 public refundRate;
|
||||
uint256 public minAllowableLockedTokens;
|
||||
uint256 public maxAllowableLockedTokens;
|
||||
uint256 public allClaimedTokens;
|
||||
uint16 public lockedPeriods;
|
||||
|
||||
/*
|
||||
* @dev WorkLock calculations:
|
||||
* depositRate = tokenSupply / ethSupply
|
||||
* claimedTokens = depositedETH * depositRate
|
||||
* refundRate = depositRate * SLOWING_REFUND / boostingRefund
|
||||
* refundETH = completedWork / refundRate
|
||||
*/
|
||||
uint256 public boostingRefund;
|
||||
uint16 public constant SLOWING_REFUND = 100;
|
||||
uint256 private constant MAX_ETH_SUPPLY = 2e10 ether;
|
||||
|
||||
uint256 public tokenSupply;
|
||||
uint256 public ethSupply;
|
||||
uint256 public unclaimedTokens;
|
||||
uint256 public lockingDuration;
|
||||
mapping(address => WorkInfo) public workInfo;
|
||||
mapping(address => address) public depositors;
|
||||
|
||||
/**
|
||||
* @param _token Token contract
|
||||
* @param _escrow Escrow contract
|
||||
* @param _router Router contract
|
||||
* @param _startBidDate Timestamp when bidding starts
|
||||
* @param _endBidDate Timestamp when bidding will end
|
||||
* @param _depositRate ETH -> NU rate
|
||||
* @param _refundRate Work -> ETH rate
|
||||
* @param _lockedPeriods Number of periods during which claimed tokens will be locked
|
||||
* @param _boostingRefund Coefficient to boost refund ETH
|
||||
* @param _lockingDuration Duration of tokens locking
|
||||
*/
|
||||
constructor(
|
||||
NuCypherToken _token,
|
||||
StakingEscrow _escrow,
|
||||
StakingInterfaceRouter _router,
|
||||
uint256 _startBidDate,
|
||||
uint256 _endBidDate,
|
||||
uint256 _depositRate,
|
||||
uint256 _refundRate,
|
||||
uint16 _lockedPeriods
|
||||
uint256 _boostingRefund,
|
||||
uint256 _lockingDuration
|
||||
)
|
||||
public
|
||||
{
|
||||
require(_token.totalSupply() > 0 &&
|
||||
uint256 totalSupply = _token.totalSupply();
|
||||
require(totalSupply > 0 &&
|
||||
_escrow.secondsPerPeriod() > 0 &&
|
||||
_router.target().isContract() &&
|
||||
_endBidDate > _startBidDate &&
|
||||
_endBidDate > block.timestamp &&
|
||||
_depositRate > 0 &&
|
||||
_refundRate > 0 &&
|
||||
_lockedPeriods >= _escrow.minLockedPeriods());
|
||||
_boostingRefund > 0 &&
|
||||
_lockingDuration > 0);
|
||||
// worst case for `ethToWork()` and `workToETH()`,
|
||||
// when ethSupply == MAX_ETH_SUPPLY and tokenSupply == totalSupply
|
||||
require(MAX_ETH_SUPPLY * totalSupply * SLOWING_REFUND / MAX_ETH_SUPPLY / totalSupply == SLOWING_REFUND &&
|
||||
MAX_ETH_SUPPLY * totalSupply * _boostingRefund / MAX_ETH_SUPPLY / totalSupply == _boostingRefund);
|
||||
|
||||
token = _token;
|
||||
escrow = _escrow;
|
||||
router = _router;
|
||||
startBidDate = _startBidDate;
|
||||
endBidDate = _endBidDate;
|
||||
minAllowableLockedTokens = _escrow.minAllowableLockedTokens();
|
||||
maxAllowableLockedTokens = _escrow.maxAllowableLockedTokens();
|
||||
depositRate = _depositRate;
|
||||
refundRate = _refundRate;
|
||||
lockedPeriods = _lockedPeriods;
|
||||
boostingRefund = _boostingRefund;
|
||||
lockingDuration = _lockingDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Bid for tokens by transferring ETH
|
||||
*/
|
||||
function bid() public payable returns (uint256 newClaimedTokens) {
|
||||
require(block.timestamp >= startBidDate && block.timestamp <= endBidDate,
|
||||
"Bid is open during a certain period");
|
||||
WorkInfo storage info = workInfo[msg.sender];
|
||||
info.depositedETH = info.depositedETH.add(msg.value);
|
||||
uint256 claimedTokens = info.depositedETH.mul(depositRate);
|
||||
require(claimedTokens >= minAllowableLockedTokens && claimedTokens <= maxAllowableLockedTokens,
|
||||
"Claimed tokens must be within the allowed limits");
|
||||
newClaimedTokens = msg.value.mul(depositRate);
|
||||
allClaimedTokens = allClaimedTokens.add(newClaimedTokens);
|
||||
require(allClaimedTokens <= token.balanceOf(address(this)),
|
||||
"Not enough tokens in the contract");
|
||||
emit Bid(msg.sender, msg.value, newClaimedTokens);
|
||||
* @notice Deposit tokens to contract
|
||||
* @param _value Amount of tokens to transfer
|
||||
**/
|
||||
function tokenDeposit(uint256 _value) external {
|
||||
require(block.timestamp <= endBidDate, "Can't deposit more tokens after end of bidding");
|
||||
token.safeTransferFrom(msg.sender, address(this), _value);
|
||||
tokenSupply += _value;
|
||||
emit Deposited(msg.sender, _value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Claimed tokens will be deposited and locked as stake in the StakingEscrow contract.
|
||||
*/
|
||||
function claim() public returns (uint256 claimedTokens) {
|
||||
require(block.timestamp >= endBidDate, "Claiming tokens allowed after bidding is over");
|
||||
WorkInfo storage info = workInfo[msg.sender];
|
||||
require(!info.claimed, "Tokens are already claimed");
|
||||
info.claimed = true;
|
||||
claimedTokens = info.depositedETH.mul(depositRate);
|
||||
info.completedWork = escrow.setWorkMeasurement(msg.sender, true);
|
||||
token.approve(address(escrow), claimedTokens);
|
||||
escrow.deposit(msg.sender, claimedTokens, lockedPeriods);
|
||||
emit Claimed(msg.sender, claimedTokens);
|
||||
* @notice Calculate amount of tokens that will be get for specified amount of ETH
|
||||
* @dev This value will be fixed only after end of bidding
|
||||
**/
|
||||
function ethToTokens(uint256 _ethAmount) public view returns (uint256) {
|
||||
return _ethAmount.mul(tokenSupply).div(ethSupply);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Refund ETH for the completed work
|
||||
*/
|
||||
function refund() public returns (uint256 refundETH) {
|
||||
WorkInfo storage info = workInfo[msg.sender];
|
||||
require(info.claimed, "Tokens are not claimed");
|
||||
require(info.depositedETH > 0, "Nothing deposited");
|
||||
uint256 currentWork = escrow.getCompletedWork(msg.sender);
|
||||
uint256 completedWork = currentWork.sub(info.completedWork);
|
||||
require(completedWork > 0, "No work that has been completed.");
|
||||
refundETH = completedWork.div(refundRate);
|
||||
if (refundETH > info.depositedETH) {
|
||||
refundETH = info.depositedETH;
|
||||
}
|
||||
if (refundETH == info.depositedETH) {
|
||||
escrow.setWorkMeasurement(msg.sender, false);
|
||||
}
|
||||
info.depositedETH = info.depositedETH.sub(refundETH);
|
||||
completedWork = refundETH.mul(refundRate);
|
||||
info.completedWork = info.completedWork.add(completedWork);
|
||||
emit Refund(msg.sender, refundETH, completedWork);
|
||||
msg.sender.sendValue(refundETH);
|
||||
* @notice Calculate amount of work that need to be done to refund specified amount of ETH
|
||||
* @dev This value will be fixed only after end of bidding
|
||||
**/
|
||||
function ethToWork(uint256 _ethAmount) public view returns (uint256) {
|
||||
return _ethAmount.mul(tokenSupply).mul(SLOWING_REFUND).divCeil(ethSupply.mul(boostingRefund));
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Calculate amount of ETH that will be refund for completing specified amount of work
|
||||
* @dev This value will be fixed only after end of bidding
|
||||
**/
|
||||
function workToETH(uint256 _completedWork) public view returns (uint256) {
|
||||
return _completedWork.mul(ethSupply).mul(boostingRefund).div(tokenSupply.mul(SLOWING_REFUND));
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get remaining work to full refund
|
||||
*/
|
||||
function getRemainingWork(address _staker) public view returns (uint256) {
|
||||
WorkInfo storage info = workInfo[_staker];
|
||||
uint256 completedWork = escrow.getCompletedWork(_staker).sub(info.completedWork);
|
||||
uint256 remainingWork = info.depositedETH.mul(refundRate);
|
||||
function getRemainingWork(address _preallocationEscrow) public view returns (uint256) {
|
||||
address depositor = depositors[_preallocationEscrow];
|
||||
WorkInfo storage info = workInfo[depositor];
|
||||
uint256 completedWork = escrow.getCompletedWork(_preallocationEscrow).sub(info.completedWork);
|
||||
uint256 remainingWork = ethToWork(info.depositedETH);
|
||||
if (remainingWork <= completedWork) {
|
||||
return 0;
|
||||
}
|
||||
return remainingWork.sub(completedWork);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Bid for tokens by transferring ETH
|
||||
*/
|
||||
function bid() external payable {
|
||||
require(block.timestamp >= startBidDate && block.timestamp <= endBidDate,
|
||||
"Bid is open during a certain period");
|
||||
WorkInfo storage info = workInfo[msg.sender];
|
||||
info.depositedETH = info.depositedETH.add(msg.value);
|
||||
ethSupply = ethSupply.add(msg.value);
|
||||
emit Bid(msg.sender, msg.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Cancel bid and refund deposited ETH
|
||||
*/
|
||||
function cancelBid() external {
|
||||
// TODO check date? check minimum amount of tokens? (#1508)
|
||||
WorkInfo storage info = workInfo[msg.sender];
|
||||
require(info.depositedETH > 0, "No bid to cancel");
|
||||
require(address(info.preallocationEscrow) == address(0), "Tokens are already claimed");
|
||||
uint256 refundETH = info.depositedETH;
|
||||
info.depositedETH = 0;
|
||||
if (block.timestamp <= endBidDate) {
|
||||
ethSupply = ethSupply.sub(refundETH);
|
||||
} else {
|
||||
unclaimedTokens = unclaimedTokens.add(ethToTokens(refundETH));
|
||||
}
|
||||
msg.sender.sendValue(refundETH);
|
||||
emit Canceled(msg.sender, refundETH);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Claimed tokens will be deposited and locked as stake in the StakingEscrow contract.
|
||||
*/
|
||||
function claim() external returns (PreallocationEscrow preallocationEscrow, uint256 claimedTokens) {
|
||||
require(block.timestamp >= endBidDate, "Claiming tokens allowed after bidding is over");
|
||||
WorkInfo storage info = workInfo[msg.sender];
|
||||
require(address(info.preallocationEscrow) == address(0), "Tokens are already claimed");
|
||||
claimedTokens = ethToTokens(info.depositedETH);
|
||||
require(claimedTokens > 0, "Nothing to claim");
|
||||
|
||||
preallocationEscrow = new PreallocationEscrow(router, token, StakingEscrowInterface(address(escrow)));
|
||||
token.approve(address(preallocationEscrow), claimedTokens);
|
||||
preallocationEscrow.initialDeposit(claimedTokens, lockingDuration);
|
||||
preallocationEscrow.transferOwnership(msg.sender);
|
||||
depositors[address(preallocationEscrow)] = msg.sender;
|
||||
info.preallocationEscrow = preallocationEscrow;
|
||||
info.completedWork = escrow.setWorkMeasurement(address(preallocationEscrow), true);
|
||||
emit Claimed(msg.sender, address(preallocationEscrow), claimedTokens);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Refund ETH for the completed work
|
||||
*/
|
||||
function refund(PreallocationEscrow _preallocationEscrow) public returns (uint256 refundETH) {
|
||||
address depositor = depositors[address(_preallocationEscrow)];
|
||||
require(depositor != address(0), "Untrusted contract");
|
||||
WorkInfo storage info = workInfo[depositor];
|
||||
require(info.depositedETH > 0, "Nothing deposited");
|
||||
require(_preallocationEscrow.owner() == msg.sender, "Only the owner of specified contract can request a refund");
|
||||
assert(_preallocationEscrow == info.preallocationEscrow);
|
||||
uint256 currentWork = escrow.getCompletedWork(address(_preallocationEscrow));
|
||||
|
||||
uint256 completedWork = currentWork.sub(info.completedWork);
|
||||
require(completedWork > 0, "No work that has been completed.");
|
||||
refundETH = workToETH(completedWork);
|
||||
|
||||
if (refundETH > info.depositedETH) {
|
||||
refundETH = info.depositedETH;
|
||||
}
|
||||
if (refundETH == info.depositedETH) {
|
||||
escrow.setWorkMeasurement(address(_preallocationEscrow), false);
|
||||
}
|
||||
info.depositedETH = info.depositedETH.sub(refundETH);
|
||||
completedWork = ethToWork(refundETH);
|
||||
|
||||
info.completedWork = info.completedWork.add(completedWork);
|
||||
emit Refund(msg.sender, address(_preallocationEscrow), refundETH, completedWork);
|
||||
msg.sender.sendValue(refundETH);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Burn unclaimed tokens
|
||||
**/
|
||||
function burnUnclaimed() public {
|
||||
require(block.timestamp >= endBidDate, "Burning tokens allowed when bidding is over");
|
||||
require(unclaimedTokens > 0, "There are no tokens that can be burned");
|
||||
token.approve(address(escrow), unclaimedTokens);
|
||||
escrow.burn(unclaimedTokens);
|
||||
emit Burnt(msg.sender, unclaimedTokens);
|
||||
unclaimedTokens = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ def _admin_actor_options(func):
|
|||
@click.option('--registry-infile', help="Input path for contract registry file", type=EXISTING_READABLE_FILE)
|
||||
@click.option('--registry-outfile', help="Output path for contract registry file", type=click.Path(file_okay=True))
|
||||
@click.option('--dev', '-d', help="Forcibly use the development registry filepath.", is_flag=True)
|
||||
@click.option('--se-test-mode', help="Enable test mode for StakingEscrow in deployment.", is_flag=True)
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
return func(*args, **kwargs)
|
||||
|
@ -138,7 +139,7 @@ def inspect(provider_uri, config_root, registry_infile, deployer_address, poa):
|
|||
@click.option('--ignore-deployed', help="Ignore already deployed contracts if exist.", is_flag=True)
|
||||
def upgrade(# Admin Actor Options
|
||||
provider_uri, contract_name, config_root, poa, force, etherscan, hw_wallet, deployer_address,
|
||||
registry_infile, registry_outfile, dev,
|
||||
registry_infile, registry_outfile, dev, se_test_mode,
|
||||
|
||||
# Other
|
||||
retarget, target_address, ignore_deployed):
|
||||
|
@ -165,7 +166,8 @@ def upgrade(# Admin Actor Options
|
|||
registry_outfile,
|
||||
hw_wallet,
|
||||
dev,
|
||||
force)
|
||||
force,
|
||||
se_test_mode)
|
||||
|
||||
if not contract_name:
|
||||
raise click.BadArgumentUsage(message="--contract-name is required when using --upgrade")
|
||||
|
@ -200,7 +202,7 @@ def upgrade(# Admin Actor Options
|
|||
@_admin_actor_options
|
||||
def rollback(# Admin Actor Options
|
||||
provider_uri, contract_name, config_root, poa, force, etherscan, hw_wallet, deployer_address,
|
||||
registry_infile, registry_outfile, dev):
|
||||
registry_infile, registry_outfile, dev, se_test_mode):
|
||||
"""
|
||||
Rollback a proxy contract's target.
|
||||
"""
|
||||
|
@ -224,7 +226,8 @@ def rollback(# Admin Actor Options
|
|||
registry_outfile,
|
||||
hw_wallet,
|
||||
dev,
|
||||
force)
|
||||
force,
|
||||
se_test_mode)
|
||||
|
||||
if not contract_name:
|
||||
raise click.BadArgumentUsage(message="--contract-name is required when using --rollback")
|
||||
|
@ -242,7 +245,7 @@ def rollback(# Admin Actor Options
|
|||
@click.option('--ignore-deployed', help="Ignore already deployed contracts if exist.", is_flag=True)
|
||||
def contracts(# Admin Actor Options
|
||||
provider_uri, contract_name, config_root, poa, force, etherscan, hw_wallet, deployer_address,
|
||||
registry_infile, registry_outfile, dev,
|
||||
registry_infile, registry_outfile, dev, se_test_mode,
|
||||
|
||||
# Other
|
||||
bare, gas, ignore_deployed):
|
||||
|
@ -269,7 +272,8 @@ def contracts(# Admin Actor Options
|
|||
registry_outfile,
|
||||
hw_wallet,
|
||||
dev,
|
||||
force)
|
||||
force,
|
||||
se_test_mode)
|
||||
|
||||
#
|
||||
# Deploy Single Contract (Amend Registry)
|
||||
|
@ -354,7 +358,7 @@ def contracts(# Admin Actor Options
|
|||
type=click.Path(exists=False, file_okay=True))
|
||||
def allocations(# Admin Actor Options
|
||||
provider_uri, contract_name, config_root, poa, force, etherscan, hw_wallet, deployer_address,
|
||||
registry_infile, registry_outfile, dev,
|
||||
registry_infile, registry_outfile, dev, se_test_mode,
|
||||
|
||||
# Other
|
||||
allocation_infile, allocation_outfile):
|
||||
|
@ -381,7 +385,8 @@ def allocations(# Admin Actor Options
|
|||
registry_outfile,
|
||||
hw_wallet,
|
||||
dev,
|
||||
force)
|
||||
force,
|
||||
se_test_mode)
|
||||
|
||||
if not allocation_infile:
|
||||
allocation_infile = click.prompt("Enter allocation data filepath")
|
||||
|
@ -398,7 +403,7 @@ def allocations(# Admin Actor Options
|
|||
@click.option('--value', help="Amount of tokens to transfer in the smallest denomination", type=click.INT)
|
||||
def transfer_tokens(# Admin Actor Options
|
||||
provider_uri, contract_name, config_root, poa, force, etherscan, hw_wallet, deployer_address,
|
||||
registry_infile, registry_outfile, dev,
|
||||
registry_infile, registry_outfile, dev, se_test_mode,
|
||||
|
||||
# Other
|
||||
target_address, value):
|
||||
|
@ -425,7 +430,8 @@ def transfer_tokens(# Admin Actor Options
|
|||
registry_outfile,
|
||||
hw_wallet,
|
||||
dev,
|
||||
force)
|
||||
force,
|
||||
se_test_mode)
|
||||
|
||||
token_agent = ContractAgency.get_agent(NucypherTokenAgent, registry=local_registry)
|
||||
if not target_address:
|
||||
|
@ -448,7 +454,7 @@ def transfer_tokens(# Admin Actor Options
|
|||
@click.option('--gas', help="Operate with a specified gas per-transaction limit", type=click.IntRange(min=1))
|
||||
def transfer_ownership(# Admin Actor Options
|
||||
provider_uri, contract_name, config_root, poa, force, etherscan, hw_wallet, deployer_address,
|
||||
registry_infile, registry_outfile, dev,
|
||||
registry_infile, registry_outfile, dev, se_test_mode,
|
||||
|
||||
# Other
|
||||
target_address, gas):
|
||||
|
@ -475,7 +481,8 @@ def transfer_ownership(# Admin Actor Options
|
|||
registry_outfile,
|
||||
hw_wallet,
|
||||
dev,
|
||||
force)
|
||||
force,
|
||||
se_test_mode)
|
||||
|
||||
if not target_address:
|
||||
target_address = click.prompt("Enter new owner's checksum address", type=EIP55_CHECKSUM_ADDRESS)
|
||||
|
@ -498,7 +505,7 @@ def transfer_ownership(# Admin Actor Options
|
|||
|
||||
|
||||
def _make_authenticated_deployment_actor(emitter, provider_uri, deployer_address, deployer_interface, contract_name,
|
||||
registry_infile, registry_outfile, hw_wallet, dev, force):
|
||||
registry_infile, registry_outfile, hw_wallet, dev, force, se_test_mode):
|
||||
#
|
||||
# Establish Registry
|
||||
#
|
||||
|
@ -525,7 +532,8 @@ def _make_authenticated_deployment_actor(emitter, provider_uri, deployer_address
|
|||
# Produce Actor
|
||||
ADMINISTRATOR = ContractAdministrator(registry=local_registry,
|
||||
client_password=password,
|
||||
deployer_address=deployer_address)
|
||||
deployer_address=deployer_address,
|
||||
staking_escrow_test_mode=se_test_mode)
|
||||
# Verify ETH Balance
|
||||
emitter.echo(f"\n\nDeployer ETH balance: {ADMINISTRATOR.eth_balance}")
|
||||
if ADMINISTRATOR.eth_balance == 0:
|
||||
|
|
|
@ -220,7 +220,8 @@ class TesterBlockchain(BlockchainDeployerInterface):
|
|||
origin = testerchain.client.etherbase
|
||||
deployer = ContractAdministrator(deployer_address=origin,
|
||||
registry=registry,
|
||||
economics=economics or cls._default_token_economics)
|
||||
economics=economics or cls._default_token_economics,
|
||||
staking_escrow_test_mode=True)
|
||||
secrets = dict()
|
||||
for deployer_class in deployer.upgradeable_deployer_classes:
|
||||
secrets[deployer_class.contract_name] = INSECURE_DEVELOPMENT_PASSWORD
|
||||
|
|
|
@ -75,14 +75,14 @@ def test_issuer(testerchain, token, deploy_contract):
|
|||
events = issuer.events.Initialized.createFilter(fromBlock='latest')
|
||||
|
||||
# Give staker tokens for reward and initialize contract
|
||||
tx = token.functions.transfer(issuer.address, economics.erc20_reward_supply).transact({'from': creator})
|
||||
tx = token.functions.approve(issuer.address, economics.erc20_reward_supply).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Only owner can initialize
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = issuer.functions.initialize().transact({'from': ursula})
|
||||
tx = issuer.functions.initialize(0).transact({'from': ursula})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = issuer.functions.initialize().transact({'from': creator})
|
||||
tx = issuer.functions.initialize(economics.erc20_reward_supply).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
events = events.get_all_entries()
|
||||
|
@ -92,7 +92,7 @@ def test_issuer(testerchain, token, deploy_contract):
|
|||
|
||||
# Can't initialize second time
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = issuer.functions.initialize().transact({'from': creator})
|
||||
tx = issuer.functions.initialize(0).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Check result of minting tokens
|
||||
|
@ -152,9 +152,9 @@ def test_inflation_rate(testerchain, token, deploy_contract):
|
|||
)
|
||||
|
||||
# Give staker tokens for reward and initialize contract
|
||||
tx = token.functions.transfer(issuer.address, economics.erc20_reward_supply).transact({'from': creator})
|
||||
tx = token.functions.approve(issuer.address, economics.erc20_reward_supply).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = issuer.functions.initialize().transact({'from': creator})
|
||||
tx = issuer.functions.initialize(economics.erc20_reward_supply).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
reward = issuer.functions.getReservedReward().call()
|
||||
|
||||
|
@ -193,9 +193,20 @@ def test_inflation_rate(testerchain, token, deploy_contract):
|
|||
# Return some tokens as a reward
|
||||
balance = token.functions.balanceOf(ursula).call()
|
||||
reward = issuer.functions.getReservedReward().call()
|
||||
tx = issuer.functions.testUnMint(2 * one_period + 2 * minted_amount).transact()
|
||||
amount_to_burn = 2 * one_period + 2 * minted_amount
|
||||
tx = token.functions.transfer(ursula, amount_to_burn).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert reward + 2 * one_period + 2 * minted_amount == issuer.functions.getReservedReward().call()
|
||||
tx = token.functions.approve(issuer.address, amount_to_burn).transact({'from': ursula})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = issuer.functions.testBurn(amount_to_burn).transact({'from': ursula})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert reward + amount_to_burn == issuer.functions.getReservedReward().call()
|
||||
|
||||
events = issuer.events.Burnt.createFilter(fromBlock=0).get_all_entries()
|
||||
assert 1 == len(events)
|
||||
event_args = events[0]['args']
|
||||
assert ursula == event_args['sender']
|
||||
assert amount_to_burn == event_args['value']
|
||||
|
||||
# Rate will be increased because some tokens were returned
|
||||
tx = issuer.functions.testMint(period + 3, 1, 1, 0).transact({'from': ursula})
|
||||
|
@ -247,9 +258,9 @@ def test_upgrading(testerchain, token, deploy_contract):
|
|||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Give tokens for reward and initialize contract
|
||||
tx = token.functions.transfer(contract.address, 10000).transact({'from': creator})
|
||||
tx = token.functions.approve(contract.address, 10000).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = contract.functions.initialize().transact({'from': creator})
|
||||
tx = contract.functions.initialize(10000).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Upgrade to the second version, check new and old values of variables
|
||||
|
|
|
@ -45,8 +45,8 @@ contract IssuerMock is Issuer {
|
|||
token.transfer(msg.sender, amount);
|
||||
}
|
||||
|
||||
function testUnMint(uint256 _amount) public {
|
||||
unMint(_amount);
|
||||
function testBurn(uint256 _value) public {
|
||||
burn(_value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,7 +19,8 @@ contract StakingEscrowBad is StakingEscrow {
|
|||
uint16 _minLockedPeriods,
|
||||
uint256 _minAllowableLockedTokens,
|
||||
uint256 _maxAllowableLockedTokens,
|
||||
uint16 _minWorkerPeriods
|
||||
uint16 _minWorkerPeriods,
|
||||
bool _isTestContract
|
||||
)
|
||||
public
|
||||
StakingEscrow(
|
||||
|
@ -31,7 +32,8 @@ contract StakingEscrowBad is StakingEscrow {
|
|||
_minLockedPeriods,
|
||||
_minAllowableLockedTokens,
|
||||
_maxAllowableLockedTokens,
|
||||
_minWorkerPeriods
|
||||
_minWorkerPeriods,
|
||||
_isTestContract
|
||||
)
|
||||
{
|
||||
}
|
||||
|
@ -60,6 +62,7 @@ contract StakingEscrowV2Mock is StakingEscrow {
|
|||
uint256 _minAllowableLockedTokens,
|
||||
uint256 _maxAllowableLockedTokens,
|
||||
uint16 _minWorkerPeriods,
|
||||
bool _isTestContract,
|
||||
uint256 _valueToCheck
|
||||
)
|
||||
public
|
||||
|
@ -72,7 +75,8 @@ contract StakingEscrowV2Mock is StakingEscrow {
|
|||
_minLockedPeriods,
|
||||
_minAllowableLockedTokens,
|
||||
_maxAllowableLockedTokens,
|
||||
_minWorkerPeriods
|
||||
_minWorkerPeriods,
|
||||
_isTestContract
|
||||
)
|
||||
{
|
||||
valueToCheck = _valueToCheck;
|
||||
|
@ -90,6 +94,7 @@ contract StakingEscrowV2Mock is StakingEscrow {
|
|||
function finishUpgrade(address _target) public onlyWhileUpgrading {
|
||||
StakingEscrowV2Mock escrow = StakingEscrowV2Mock(_target);
|
||||
valueToCheck = escrow.valueToCheck();
|
||||
isTestContract = escrow.isTestContract();
|
||||
emit UpgradeFinished(_target, msg.sender);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,4 +56,14 @@ contract StakingEscrowForWorkLockMock {
|
|||
stakerInfo[_staker].completedWork = _completedWork;
|
||||
}
|
||||
|
||||
function burn(uint256 _value) public {
|
||||
token.transferFrom(msg.sender, address(this), _value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @notice Contract for using in WorkLock tests
|
||||
**/
|
||||
contract StakingInterfaceMock {}
|
||||
|
|
|
@ -20,7 +20,7 @@ import os
|
|||
|
||||
import pytest
|
||||
from eth_tester.exceptions import TransactionFailed
|
||||
from eth_utils import to_canonical_address
|
||||
from eth_utils import to_canonical_address, to_wei
|
||||
from web3.contract import Contract
|
||||
|
||||
from nucypher.blockchain.economics import TokenEconomics
|
||||
|
@ -70,7 +70,7 @@ def token(token_economics, deploy_contract):
|
|||
def escrow(testerchain, token, token_economics, deploy_contract):
|
||||
# Creator deploys the escrow
|
||||
contract, _ = deploy_contract(
|
||||
'StakingEscrow', token.address, *token_economics.staking_deployment_parameters
|
||||
'StakingEscrow', token.address, *token_economics.staking_deployment_parameters, True
|
||||
)
|
||||
|
||||
secret_hash = testerchain.w3.keccak(escrow_secret)
|
||||
|
@ -134,34 +134,6 @@ def adjudicator(testerchain, escrow, token_economics, deploy_contract):
|
|||
return contract, dispatcher
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def worklock(testerchain, token, escrow, deploy_contract):
|
||||
escrow, _ = escrow
|
||||
creator = testerchain.w3.eth.accounts[0]
|
||||
|
||||
# Creator deploys the worklock using test values
|
||||
now = testerchain.w3.eth.getBlock(block_identifier='latest').timestamp
|
||||
start_bid_date = ((now + 3600) // 3600 + 1) * 3600 # beginning of the next hour plus 1 hour
|
||||
end_bid_date = start_bid_date + 3600
|
||||
deposit_rate = 2
|
||||
refund_rate = deposit_rate
|
||||
contract, _ = deploy_contract(
|
||||
contract_name='WorkLock',
|
||||
_token=token.address,
|
||||
_escrow=escrow.address,
|
||||
_startBidDate=start_bid_date,
|
||||
_endBidDate=end_bid_date,
|
||||
_depositRate=deposit_rate,
|
||||
_refundRate=refund_rate,
|
||||
_lockedPeriods=6
|
||||
)
|
||||
|
||||
tx = escrow.functions.setWorkLock(contract.address).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
return contract
|
||||
|
||||
|
||||
def mock_ursula(testerchain, account, mocker):
|
||||
ursula_privkey = UmbralPrivateKey.gen_key()
|
||||
ursula_stamp = SignatureStamp(verifying_key=ursula_privkey.pubkey,
|
||||
|
@ -195,6 +167,35 @@ def staking_interface(testerchain, token, escrow, policy_manager, deploy_contrac
|
|||
return staking_interface, router
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def worklock(testerchain, token, escrow, staking_interface, deploy_contract):
|
||||
escrow, _ = escrow
|
||||
creator = testerchain.w3.eth.accounts[0]
|
||||
_, router = staking_interface
|
||||
|
||||
# Creator deploys the worklock using test values
|
||||
now = testerchain.w3.eth.getBlock(block_identifier='latest').timestamp
|
||||
start_bid_date = ((now + 3600) // 3600 + 1) * 3600 # beginning of the next hour plus 1 hour
|
||||
end_bid_date = start_bid_date + 3600
|
||||
boosting_refund = 100
|
||||
locking_duration = 20 * 60 * 60
|
||||
contract, _ = deploy_contract(
|
||||
contract_name='WorkLock',
|
||||
_token=token.address,
|
||||
_escrow=escrow.address,
|
||||
_router=router.address,
|
||||
_startBidDate=start_bid_date,
|
||||
_endBidDate=end_bid_date,
|
||||
_boostingRefund=boosting_refund,
|
||||
_lockingDuration=locking_duration
|
||||
)
|
||||
|
||||
tx = escrow.functions.setWorkLock(contract.address).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
return contract
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def multisig(testerchain, escrow, policy_manager, adjudicator, staking_interface, deploy_contract):
|
||||
escrow, escrow_dispatcher = escrow
|
||||
|
@ -268,6 +269,14 @@ def test_all(testerchain,
|
|||
testerchain.client.accounts
|
||||
contracts_owners = sorted(contracts_owners)
|
||||
|
||||
# Create the first preallocation escrow
|
||||
preallocation_escrow_1, _ = deploy_contract(
|
||||
'PreallocationEscrow', staking_interface_router.address, token.address, escrow.address)
|
||||
preallocation_escrow_interface_1 = testerchain.client.get_contract(
|
||||
abi=staking_interface.abi,
|
||||
address=preallocation_escrow_1.address,
|
||||
ContractFactoryClass=Contract)
|
||||
|
||||
# We'll need this later for slashing these Ursulas
|
||||
ursula1_with_stamp = mock_ursula(testerchain, ursula1, mocker=mocker)
|
||||
ursula2_with_stamp = mock_ursula(testerchain, ursula2, mocker=mocker)
|
||||
|
@ -307,50 +316,61 @@ def test_all(testerchain,
|
|||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Initialize escrow
|
||||
tx = token.functions.transfer(escrow.address, token_economics.erc20_reward_supply).transact({'from': creator})
|
||||
tx = token.functions.transfer(multisig.address, token_economics.erc20_reward_supply).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = escrow.functions.initialize().buildTransaction({'from': multisig.address, 'gasPrice': 0})
|
||||
tx = token.functions.approve(escrow.address, token_economics.erc20_reward_supply)\
|
||||
.buildTransaction({'from': multisig.address, 'gasPrice': 0})
|
||||
execute_multisig_transaction(testerchain, multisig, [contracts_owners[0], contracts_owners[1]], tx)
|
||||
tx = escrow.functions.initialize(token_economics.erc20_reward_supply)\
|
||||
.buildTransaction({'from': multisig.address, 'gasPrice': 0})
|
||||
execute_multisig_transaction(testerchain, multisig, [contracts_owners[0], contracts_owners[1]], tx)
|
||||
|
||||
# Initialize worklock
|
||||
initial_supply = 1000
|
||||
tx = token.functions.transfer(worklock.address, initial_supply).transact({'from': creator})
|
||||
worklock_supply = 1980
|
||||
tx = token.functions.approve(worklock.address, worklock_supply).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = worklock.functions.tokenDeposit(worklock_supply).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Can't do anything before start date
|
||||
deposit_rate = 2
|
||||
refund_rate = 2
|
||||
deposited_eth = 1000 // deposit_rate
|
||||
deposited_eth_1 = to_wei(18, 'ether')
|
||||
deposited_eth_2 = to_wei(1, 'ether')
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.bid().transact({'from': ursula2, 'value': deposited_eth, 'gas_price': 0})
|
||||
tx = worklock.functions.bid().transact({'from': ursula2, 'value': deposited_eth_1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Wait for the start of the bidding
|
||||
testerchain.time_travel(hours=1)
|
||||
|
||||
# Can't bid with too low or too high ETH
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.bid().transact({'from': ursula2, 'value': 1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.bid().transact({'from': ursula2, 'value': 10**10, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Ursula does bid
|
||||
assert worklock.functions.allClaimedTokens().call() == 0
|
||||
assert worklock.functions.workInfo(ursula2).call()[0] == 0
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == 0
|
||||
tx = worklock.functions.bid().transact({'from': ursula2, 'value': deposited_eth, 'gas_price': 0})
|
||||
tx = worklock.functions.bid().transact({'from': ursula2, 'value': deposited_eth_1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.allClaimedTokens().call() == 1000
|
||||
assert worklock.functions.workInfo(ursula2).call()[0] == deposited_eth
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == deposited_eth
|
||||
assert worklock.functions.workInfo(ursula2).call()[0] == deposited_eth_1
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == deposited_eth_1
|
||||
assert worklock.functions.ethToTokens(deposited_eth_1).call() == worklock_supply
|
||||
|
||||
# Can't claim while bidding phase
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.claim().transact({'from': ursula2, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Other Ursula do bid
|
||||
assert worklock.functions.workInfo(ursula1).call()[0] == 0
|
||||
tx = worklock.functions.bid().transact({'from': ursula1, 'value': deposited_eth_2, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.workInfo(ursula1).call()[0] == deposited_eth_2
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == deposited_eth_1 + deposited_eth_2
|
||||
assert worklock.functions.ethToTokens(deposited_eth_2).call() == worklock_supply // 19
|
||||
|
||||
assert worklock.functions.workInfo(ursula4).call()[0] == 0
|
||||
tx = worklock.functions.bid().transact({'from': ursula4, 'value': deposited_eth_2, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.workInfo(ursula4).call()[0] == deposited_eth_2
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == deposited_eth_1 + 2 * deposited_eth_2
|
||||
assert worklock.functions.ethToTokens(deposited_eth_2).call() == worklock_supply // 20
|
||||
|
||||
# Wait for the end of the bidding
|
||||
testerchain.time_travel(hours=1)
|
||||
|
||||
|
@ -359,29 +379,81 @@ def test_all(testerchain,
|
|||
tx = worklock.functions.bid().transact({'from': ursula2, 'value': 1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# One of Ursulas cancels bid
|
||||
tx = worklock.functions.cancelBid().transact({'from': ursula1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.workInfo(ursula1).call()[0] == 0
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == deposited_eth_1 + deposited_eth_2
|
||||
assert worklock.functions.ethToTokens(deposited_eth_2).call() == worklock_supply // 20
|
||||
assert worklock.functions.unclaimedTokens().call() == worklock_supply // 20
|
||||
|
||||
# Ursula claims tokens
|
||||
tx = worklock.functions.claim().transact({'from': ursula2, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.getRemainingWork(ursula2).call() == deposit_rate * deposited_eth
|
||||
assert token_economics.erc20_reward_supply + 1000 == token.functions.balanceOf(escrow.address).call()
|
||||
assert 1000 == escrow.functions.getAllTokens(ursula2).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(ursula2, 0).call()
|
||||
assert 1000 == escrow.functions.getLockedTokens(ursula2, 1).call()
|
||||
assert 1000 == escrow.functions.getLockedTokens(ursula2, 6).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(ursula2, 7).call()
|
||||
assert 0 == escrow.functions.getCompletedWork(ursula2).call()
|
||||
preallocation_escrow_2 = testerchain.client.get_contract(
|
||||
abi=preallocation_escrow_1.abi,
|
||||
address=worklock.functions.workInfo(ursula2).call()[2],
|
||||
ContractFactoryClass=Contract)
|
||||
|
||||
tx = escrow.functions.setWorker(ursula2).transact({'from': ursula2})
|
||||
ursula2_tokens = worklock_supply * 9 // 10
|
||||
assert token.functions.balanceOf(ursula2).call() == 0
|
||||
assert token.functions.balanceOf(preallocation_escrow_2.address).call() == ursula2_tokens
|
||||
assert preallocation_escrow_2.functions.owner().call() == ursula2
|
||||
assert preallocation_escrow_2.functions.getLockedTokens().call() == ursula2_tokens
|
||||
ursula2_remaining_work = ursula2_tokens
|
||||
assert worklock.functions.ethToWork(deposited_eth_1).call() == ursula2_remaining_work
|
||||
assert worklock.functions.workToETH(ursula2_remaining_work).call() == deposited_eth_1
|
||||
assert worklock.functions.getRemainingWork(preallocation_escrow_2.address).call() == ursula2_remaining_work
|
||||
assert token.functions.balanceOf(worklock.address).call() == worklock_supply - ursula2_tokens
|
||||
|
||||
preallocation_escrow_interface_2 = testerchain.client.get_contract(
|
||||
abi=staking_interface.abi,
|
||||
address=preallocation_escrow_2.address,
|
||||
ContractFactoryClass=Contract)
|
||||
tx = preallocation_escrow_interface_2.functions.depositAsStaker(1000, 6).transact({'from': ursula2})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = preallocation_escrow_interface_2.functions.setWorker(ursula2).transact({'from': ursula2})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
escrow_balance = token_economics.erc20_reward_supply + 1000
|
||||
assert 1000 == escrow.functions.getAllTokens(preallocation_escrow_2.address).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(preallocation_escrow_2.address, 0).call()
|
||||
assert 1000 == escrow.functions.getLockedTokens(preallocation_escrow_2.address, 1).call()
|
||||
assert 1000 == escrow.functions.getLockedTokens(preallocation_escrow_2.address, 6).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(preallocation_escrow_2.address, 7).call()
|
||||
assert 0 == escrow.functions.getCompletedWork(preallocation_escrow_2.address).call()
|
||||
|
||||
# Another Ursula claims tokens
|
||||
tx = worklock.functions.claim().transact({'from': ursula4, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
preallocation_escrow_3 = testerchain.client.get_contract(
|
||||
abi=preallocation_escrow_1.abi,
|
||||
address=worklock.functions.workInfo(ursula4).call()[2],
|
||||
ContractFactoryClass=Contract)
|
||||
|
||||
ursula4_tokens = worklock_supply // 20
|
||||
assert token.functions.balanceOf(ursula4).call() == 0
|
||||
assert token.functions.balanceOf(preallocation_escrow_3.address).call() == ursula4_tokens
|
||||
assert preallocation_escrow_3.functions.owner().call() == ursula4
|
||||
assert preallocation_escrow_3.functions.getLockedTokens().call() == ursula4_tokens
|
||||
assert token.functions.balanceOf(worklock.address).call() == worklock_supply - ursula2_tokens - ursula4_tokens
|
||||
|
||||
# Burn remaining tokens in WorkLock
|
||||
tx = worklock.functions.burnUnclaimed().transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
escrow_balance += worklock_supply // 20
|
||||
assert 0 == worklock.functions.unclaimedTokens().call()
|
||||
assert 0 == token.functions.balanceOf(worklock.address).call()
|
||||
assert escrow_balance == token.functions.balanceOf(escrow.address).call()
|
||||
assert token_economics.erc20_reward_supply + worklock_supply // 20 == escrow.functions.getReservedReward().call()
|
||||
|
||||
# Ursula prolongs lock duration
|
||||
tx = escrow.functions.prolongStake(0, 3).transact({'from': ursula2, 'gas_price': 0})
|
||||
tx = preallocation_escrow_interface_2.functions.prolongStake(0, 3).transact({'from': ursula2, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert 0 == escrow.functions.getLockedTokens(ursula2, 0).call()
|
||||
assert 1000 == escrow.functions.getLockedTokens(ursula2, 1).call()
|
||||
assert 1000 == escrow.functions.getLockedTokens(ursula2, 9).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(ursula2, 10).call()
|
||||
assert 0 == escrow.functions.getCompletedWork(ursula2).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(preallocation_escrow_2.address, 0).call()
|
||||
assert 1000 == escrow.functions.getLockedTokens(preallocation_escrow_2.address, 1).call()
|
||||
assert 1000 == escrow.functions.getLockedTokens(preallocation_escrow_2.address, 9).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(preallocation_escrow_2.address, 10).call()
|
||||
assert 0 == escrow.functions.getCompletedWork(preallocation_escrow_2.address).call()
|
||||
|
||||
# Can't claim more than once
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
|
@ -389,16 +461,10 @@ def test_all(testerchain,
|
|||
testerchain.wait_for_receipt(tx)
|
||||
# Can't refund without work
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.refund().transact({'from': ursula2, 'gas_price': 0})
|
||||
tx = worklock.functions.refund(preallocation_escrow_2.address).transact({'from': ursula2, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Create the first preallocation escrow, set and lock re-stake parameter
|
||||
preallocation_escrow_1, _ = deploy_contract(
|
||||
'PreallocationEscrow', staking_interface_router.address, token.address, escrow.address)
|
||||
preallocation_escrow_interface_1 = testerchain.client.get_contract(
|
||||
abi=staking_interface.abi,
|
||||
address=preallocation_escrow_1.address,
|
||||
ContractFactoryClass=Contract)
|
||||
# Set and lock re-stake parameter in first preallocation escrow
|
||||
tx = preallocation_escrow_1.functions.transferOwnership(ursula3).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert not escrow.functions.stakerInfo(preallocation_escrow_1.address).call()[RE_STAKE_FIELD]
|
||||
|
@ -419,22 +485,10 @@ def test_all(testerchain,
|
|||
tx = preallocation_escrow_1.functions.initialDeposit(10000, 20 * 60 * 60).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
preallocation_escrow_2, _ = deploy_contract(
|
||||
'PreallocationEscrow', staking_interface_router.address, token.address, escrow.address)
|
||||
tx = preallocation_escrow_2.functions.transferOwnership(ursula4).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = token.functions.approve(preallocation_escrow_2.address, 10000).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = preallocation_escrow_2.functions.initialDeposit(10000, 20 * 60 * 60).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert 10000 == token.functions.balanceOf(preallocation_escrow_1.address).call()
|
||||
assert ursula3 == preallocation_escrow_1.functions.owner().call()
|
||||
assert 10000 >= preallocation_escrow_1.functions.getLockedTokens().call()
|
||||
assert 9500 <= preallocation_escrow_1.functions.getLockedTokens().call()
|
||||
assert 10000 == token.functions.balanceOf(preallocation_escrow_2.address).call()
|
||||
assert ursula4 == preallocation_escrow_2.functions.owner().call()
|
||||
assert 10000 >= preallocation_escrow_2.functions.getLockedTokens().call()
|
||||
assert 9500 <= preallocation_escrow_2.functions.getLockedTokens().call()
|
||||
|
||||
# Ursula's withdrawal attempt won't succeed because nothing to withdraw
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
|
@ -453,6 +507,7 @@ def test_all(testerchain,
|
|||
assert 0 == escrow.functions.getLockedTokens(ursula4, 0).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(preallocation_escrow_1.address, 0).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(preallocation_escrow_2.address, 0).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(preallocation_escrow_3.address, 0).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(contracts_owners[0], 0).call()
|
||||
|
||||
# Ursula can't deposit and lock too low value
|
||||
|
@ -476,7 +531,8 @@ def test_all(testerchain,
|
|||
testerchain.wait_for_receipt(tx)
|
||||
tx = escrow.functions.confirmActivity().transact({'from': ursula1})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert token_economics.erc20_reward_supply + 2000 == token.functions.balanceOf(escrow.address).call()
|
||||
escrow_balance += 1000
|
||||
assert escrow_balance == token.functions.balanceOf(escrow.address).call()
|
||||
assert 9000 == token.functions.balanceOf(ursula1).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(ursula1, 0).call()
|
||||
assert 1000 == escrow.functions.getLockedTokens(ursula1, 1).call()
|
||||
|
@ -491,12 +547,13 @@ def test_all(testerchain,
|
|||
testerchain.wait_for_receipt(tx)
|
||||
tx = escrow.functions.confirmActivity().transact({'from': ursula3})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
escrow_balance += 1000
|
||||
assert 1000 == escrow.functions.getAllTokens(preallocation_escrow_1.address).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(preallocation_escrow_1.address, 0).call()
|
||||
assert 1000 == escrow.functions.getLockedTokens(preallocation_escrow_1.address, 1).call()
|
||||
assert 1000 == escrow.functions.getLockedTokens(preallocation_escrow_1.address, 10).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(preallocation_escrow_1.address, 11).call()
|
||||
assert token_economics.erc20_reward_supply + 3000 == token.functions.balanceOf(escrow.address).call()
|
||||
assert escrow_balance == token.functions.balanceOf(escrow.address).call()
|
||||
assert 9000 == token.functions.balanceOf(preallocation_escrow_1.address).call()
|
||||
|
||||
# Only owner can deposit tokens to the staking escrow
|
||||
|
@ -509,7 +566,7 @@ def test_all(testerchain,
|
|||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Divide stakes
|
||||
tx = escrow.functions.divideStake(0, 500, 6).transact({'from': ursula2})
|
||||
tx = preallocation_escrow_interface_2.functions.divideStake(0, 500, 6).transact({'from': ursula2})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = escrow.functions.divideStake(0, 500, 9).transact({'from': ursula1})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
@ -544,12 +601,13 @@ def test_all(testerchain,
|
|||
|
||||
# Create policies
|
||||
policy_id_1 = os.urandom(16)
|
||||
tx = policy_manager.functions.createPolicy(policy_id_1, 5, 44, [ursula1, ursula2]) \
|
||||
tx = policy_manager.functions.createPolicy(policy_id_1, 5, 44, [ursula1, preallocation_escrow_2.address]) \
|
||||
.transact({'from': alice1, 'value': 2 * 1000 + 2 * 44, 'gas_price': 0})
|
||||
|
||||
testerchain.wait_for_receipt(tx)
|
||||
policy_id_2 = os.urandom(16)
|
||||
tx = policy_manager.functions.createPolicy(policy_id_2, 5, 44, [ursula2, preallocation_escrow_1.address]) \
|
||||
tx = policy_manager.functions\
|
||||
.createPolicy(policy_id_2, 5, 44, [preallocation_escrow_2.address, preallocation_escrow_1.address]) \
|
||||
.transact({'from': alice1, 'value': 2 * 1000 + 2 * 44, 'gas_price': 0})
|
||||
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
@ -559,12 +617,13 @@ def test_all(testerchain,
|
|||
|
||||
testerchain.wait_for_receipt(tx)
|
||||
policy_id_4 = os.urandom(16)
|
||||
tx = policy_manager.functions.createPolicy(policy_id_4, 5, 44, [ursula2, preallocation_escrow_1.address]) \
|
||||
tx = policy_manager.functions\
|
||||
.createPolicy(policy_id_4, 5, 44, [preallocation_escrow_2.address, preallocation_escrow_1.address]) \
|
||||
.transact({'from': alice2, 'value': 2 * 1000 + 2 * 44, 'gas_price': 0})
|
||||
|
||||
testerchain.wait_for_receipt(tx)
|
||||
policy_id_5 = os.urandom(16)
|
||||
tx = policy_manager.functions.createPolicy(policy_id_5, 5, 44, [ursula1, ursula2]) \
|
||||
tx = policy_manager.functions.createPolicy(policy_id_5, 5, 44, [ursula1, preallocation_escrow_2.address]) \
|
||||
.transact({'from': alice2, 'value': 2 * 1000 + 2 * 44, 'gas_price': 0})
|
||||
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
@ -589,8 +648,8 @@ def test_all(testerchain,
|
|||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
alice1_balance = testerchain.client.get_balance(alice1)
|
||||
tx = policy_manager.functions.revokeArrangement(policy_id_2, ursula2).transact({'from': alice1, 'gas_price': 0})
|
||||
|
||||
tx = policy_manager.functions.revokeArrangement(policy_id_2, preallocation_escrow_2.address)\
|
||||
.transact({'from': alice1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert 7440 == testerchain.client.get_balance(policy_manager.address)
|
||||
assert alice1_balance + 1000 == testerchain.client.get_balance(alice1)
|
||||
|
@ -598,7 +657,8 @@ def test_all(testerchain,
|
|||
|
||||
# Can't revoke again
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = policy_manager.functions.revokeArrangement(policy_id_2, ursula2).transact({'from': alice1})
|
||||
tx = policy_manager.functions.revokeArrangement(policy_id_2, preallocation_escrow_2.address)\
|
||||
.transact({'from': alice1})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Wait, confirm activity, mint
|
||||
|
@ -611,8 +671,8 @@ def test_all(testerchain,
|
|||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Check work measurement
|
||||
work_done = escrow.functions.getCompletedWork(ursula2).call()
|
||||
assert 0 < work_done
|
||||
completed_work = escrow.functions.getCompletedWork(preallocation_escrow_2.address).call()
|
||||
assert 0 < completed_work
|
||||
assert 0 == escrow.functions.getCompletedWork(preallocation_escrow_1.address).call()
|
||||
assert 0 == escrow.functions.getCompletedWork(ursula1).call()
|
||||
|
||||
|
@ -649,7 +709,7 @@ def test_all(testerchain,
|
|||
testerchain.wait_for_receipt(tx)
|
||||
assert ursula1_balance < testerchain.client.get_balance(ursula1)
|
||||
ursula2_balance = testerchain.client.get_balance(ursula2)
|
||||
tx = policy_manager.functions.withdraw().transact({'from': ursula2, 'gas_price': 0})
|
||||
tx = preallocation_escrow_interface_2.functions.withdrawPolicyReward(ursula2).transact({'from': ursula2, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert ursula2_balance < testerchain.client.get_balance(ursula2)
|
||||
ursula3_balance = testerchain.client.get_balance(ursula3)
|
||||
|
@ -682,7 +742,7 @@ def test_all(testerchain,
|
|||
policy_manager_v1 = policy_manager.functions.target().call()
|
||||
# Creator deploys the contracts as the second versions
|
||||
escrow_v2, _ = deploy_contract(
|
||||
'StakingEscrow', token.address, *token_economics.staking_deployment_parameters
|
||||
'StakingEscrow', token.address, *token_economics.staking_deployment_parameters, False
|
||||
)
|
||||
policy_manager_v2, _ = deploy_contract('PolicyManager', escrow.address)
|
||||
# Ursula and Alice can't upgrade contracts, only owner can
|
||||
|
@ -850,22 +910,22 @@ def test_all(testerchain,
|
|||
assert alice1_balance + base_penalty / reward_coefficient == token.functions.balanceOf(alice1).call()
|
||||
|
||||
# Slash part of the one sub stake
|
||||
tokens_amount = escrow.functions.getAllTokens(ursula2).call()
|
||||
unlocked_amount = tokens_amount - escrow.functions.getLockedTokens(ursula2, 0).call()
|
||||
tx = escrow.functions.withdraw(unlocked_amount).transact({'from': ursula2})
|
||||
tokens_amount = escrow.functions.getAllTokens(preallocation_escrow_2.address).call()
|
||||
unlocked_amount = tokens_amount - escrow.functions.getLockedTokens(preallocation_escrow_2.address, 0).call()
|
||||
tx = preallocation_escrow_interface_2.functions.withdrawAsStaker(unlocked_amount).transact({'from': ursula2})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
previous_lock = escrow.functions.getLockedTokensInPast(ursula2, 1).call()
|
||||
lock = escrow.functions.getLockedTokens(ursula2, 0).call()
|
||||
next_lock = escrow.functions.getLockedTokens(ursula2, 1).call()
|
||||
previous_lock = escrow.functions.getLockedTokensInPast(preallocation_escrow_2.address, 1).call()
|
||||
lock = escrow.functions.getLockedTokens(preallocation_escrow_2.address, 0).call()
|
||||
next_lock = escrow.functions.getLockedTokens(preallocation_escrow_2.address, 1).call()
|
||||
data_hash, slashing_args = generate_args_for_slashing(mock_ursula_reencrypts, ursula2_with_stamp)
|
||||
assert not adjudicator.functions.evaluatedCFrags(data_hash).call()
|
||||
tx = adjudicator.functions.evaluateCFrag(*slashing_args).transact({'from': alice1})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert adjudicator.functions.evaluatedCFrags(data_hash).call()
|
||||
assert lock - base_penalty == escrow.functions.getAllTokens(ursula2).call()
|
||||
assert previous_lock == escrow.functions.getLockedTokensInPast(ursula2, 1).call()
|
||||
assert lock - base_penalty == escrow.functions.getLockedTokens(ursula2, 0).call()
|
||||
assert next_lock - base_penalty == escrow.functions.getLockedTokens(ursula2, 1).call()
|
||||
assert lock - base_penalty == escrow.functions.getAllTokens(preallocation_escrow_2.address).call()
|
||||
assert previous_lock == escrow.functions.getLockedTokensInPast(preallocation_escrow_2.address, 1).call()
|
||||
assert lock - base_penalty == escrow.functions.getLockedTokens(preallocation_escrow_2.address, 0).call()
|
||||
assert next_lock - base_penalty == escrow.functions.getLockedTokens(preallocation_escrow_2.address, 1).call()
|
||||
assert total_previous_lock == escrow.functions.lockedPerPeriod(current_period - 1).call()
|
||||
assert total_lock - base_penalty == escrow.functions.lockedPerPeriod(current_period).call()
|
||||
assert 0 == escrow.functions.lockedPerPeriod(current_period + 1).call()
|
||||
|
@ -986,7 +1046,7 @@ def test_all(testerchain,
|
|||
|
||||
# Can't prolong stake by too low duration
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = escrow.functions.prolongStake(0, 1).transact({'from': ursula2, 'gas_price': 0})
|
||||
tx = preallocation_escrow_interface_2.functions.prolongStake(0, 1).transact({'from': ursula2, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Unlock and withdraw all tokens
|
||||
|
@ -1012,7 +1072,7 @@ def test_all(testerchain,
|
|||
|
||||
tx = escrow.functions.mint().transact({'from': ursula1})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = escrow.functions.mint().transact({'from': ursula2})
|
||||
tx = preallocation_escrow_interface_2.functions.mint().transact({'from': ursula2})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = preallocation_escrow_interface_1.functions.mint().transact({'from': ursula3})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
@ -1023,51 +1083,51 @@ def test_all(testerchain,
|
|||
assert 0 == escrow.functions.getLockedTokens(ursula4, 0).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(preallocation_escrow_1.address, 0).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(preallocation_escrow_2.address, 0).call()
|
||||
assert 0 == escrow.functions.getLockedTokens(preallocation_escrow_3.address, 0).call()
|
||||
|
||||
ursula1_balance = token.functions.balanceOf(ursula1).call()
|
||||
ursula2_balance = token.functions.balanceOf(ursula2).call()
|
||||
ursula2_balance = token.functions.balanceOf(preallocation_escrow_2.address).call()
|
||||
preallocation_escrow_1_balance = token.functions.balanceOf(preallocation_escrow_1.address).call()
|
||||
tokens_amount = escrow.functions.getAllTokens(ursula1).call()
|
||||
tx = escrow.functions.withdraw(tokens_amount).transact({'from': ursula1})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tokens_amount = escrow.functions.getAllTokens(ursula2).call()
|
||||
tx = escrow.functions.withdraw(tokens_amount).transact({'from': ursula2})
|
||||
tokens_amount = escrow.functions.getAllTokens(preallocation_escrow_2.address).call()
|
||||
tx = preallocation_escrow_interface_2.functions.withdrawAsStaker(tokens_amount).transact({'from': ursula2})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tokens_amount = escrow.functions.getAllTokens(preallocation_escrow_1.address).call()
|
||||
tx = preallocation_escrow_interface_1.functions.withdrawAsStaker(tokens_amount).transact({'from': ursula3})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert ursula1_balance < token.functions.balanceOf(ursula1).call()
|
||||
assert ursula2_balance < token.functions.balanceOf(ursula2).call()
|
||||
assert ursula2_balance < token.functions.balanceOf(preallocation_escrow_2.address).call()
|
||||
assert preallocation_escrow_1_balance < token.functions.balanceOf(preallocation_escrow_1.address).call()
|
||||
|
||||
# Unlock and withdraw all tokens in PreallocationEscrow
|
||||
testerchain.time_travel(hours=1)
|
||||
assert 0 == preallocation_escrow_1.functions.getLockedTokens().call()
|
||||
assert 0 == preallocation_escrow_2.functions.getLockedTokens().call()
|
||||
assert 0 == preallocation_escrow_3.functions.getLockedTokens().call()
|
||||
ursula3_balance = token.functions.balanceOf(ursula3).call()
|
||||
ursula4_balance = token.functions.balanceOf(ursula4).call()
|
||||
tokens_amount = token.functions.balanceOf(preallocation_escrow_1.address).call()
|
||||
tx = preallocation_escrow_1.functions.withdrawTokens(tokens_amount).transact({'from': ursula3})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tokens_amount = token.functions.balanceOf(preallocation_escrow_2.address).call()
|
||||
tx = preallocation_escrow_2.functions.withdrawTokens(tokens_amount).transact({'from': ursula4})
|
||||
tokens_amount = token.functions.balanceOf(preallocation_escrow_3.address).call()
|
||||
tx = preallocation_escrow_3.functions.withdrawTokens(tokens_amount).transact({'from': ursula4})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert ursula3_balance < token.functions.balanceOf(ursula3).call()
|
||||
assert ursula4_balance < token.functions.balanceOf(ursula4).call()
|
||||
|
||||
# Partial refund for Ursula
|
||||
new_work_done = escrow.functions.getCompletedWork(ursula2).call()
|
||||
assert work_done < new_work_done
|
||||
remaining_work = worklock.functions.getRemainingWork(ursula2).call()
|
||||
new_completed_work = escrow.functions.getCompletedWork(preallocation_escrow_2.address).call()
|
||||
assert completed_work < new_completed_work
|
||||
remaining_work = worklock.functions.getRemainingWork(preallocation_escrow_2.address).call()
|
||||
assert 0 < remaining_work
|
||||
assert deposited_eth == worklock.functions.workInfo(ursula2).call()[0]
|
||||
assert deposited_eth_1 == worklock.functions.workInfo(ursula2).call()[0]
|
||||
ursula2_balance = testerchain.w3.eth.getBalance(ursula2)
|
||||
tx = worklock.functions.refund().transact({'from': ursula2, 'gas_price': 0})
|
||||
tx = worklock.functions.refund(preallocation_escrow_2.address).transact({'from': ursula2, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
refund = new_work_done // refund_rate
|
||||
assert deposited_eth - refund == worklock.functions.workInfo(ursula2).call()[0]
|
||||
refund = worklock.functions.workToETH(new_completed_work).call()
|
||||
assert deposited_eth_1 - refund == worklock.functions.workInfo(ursula2).call()[0]
|
||||
assert refund + ursula2_balance == testerchain.w3.eth.getBalance(ursula2)
|
||||
assert remaining_work == worklock.functions.getRemainingWork(ursula2).call()
|
||||
assert deposited_eth - refund == testerchain.w3.eth.getBalance(worklock.address)
|
||||
assert deposited_eth_1 + deposited_eth_2 - refund == testerchain.w3.eth.getBalance(worklock.address)
|
||||
assert 0 == escrow.functions.getCompletedWork(ursula1).call()
|
||||
assert 0 == escrow.functions.getCompletedWork(preallocation_escrow_1.address).call()
|
||||
|
|
|
@ -55,6 +55,7 @@ def escrow_contract(testerchain, token, token_economics, request, deploy_contrac
|
|||
# Creator deploys the escrow
|
||||
deploy_parameters = list(token_economics.staking_deployment_parameters)
|
||||
deploy_parameters[-2] = max_allowed_locked_tokens
|
||||
deploy_parameters.append(True)
|
||||
contract, _ = deploy_contract('StakingEscrow', token.address, *deploy_parameters)
|
||||
|
||||
if request.param:
|
||||
|
|
|
@ -49,9 +49,9 @@ def test_mining(testerchain, token, escrow_contract, token_economics):
|
|||
withdraw_log = escrow.events.Withdrawn.createFilter(fromBlock='latest')
|
||||
|
||||
# Give Escrow tokens for reward and initialize contract
|
||||
tx = token.functions.transfer(escrow.address, token_economics.erc20_reward_supply).transact({'from': creator})
|
||||
tx = token.functions.approve(escrow.address, token_economics.erc20_reward_supply).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = escrow.functions.initialize().transact({'from': creator})
|
||||
tx = escrow.functions.initialize(token_economics.erc20_reward_supply).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Give Ursula and Ursula(2) some coins
|
||||
|
@ -366,9 +366,9 @@ def test_slashing(testerchain, token, escrow_contract, token_economics, deploy_c
|
|||
slashing_log = escrow.events.Slashed.createFilter(fromBlock='latest')
|
||||
|
||||
# Give Escrow tokens for reward and initialize contract
|
||||
tx = token.functions.transfer(escrow.address, token_economics.erc20_reward_supply).transact({'from': creator})
|
||||
tx = token.functions.approve(escrow.address, token_economics.erc20_reward_supply).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = escrow.functions.initialize().transact({'from': creator})
|
||||
tx = escrow.functions.initialize(token_economics.erc20_reward_supply).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Give Ursula deposit some tokens
|
||||
|
|
|
@ -77,7 +77,7 @@ def test_staking(testerchain, token, escrow_contract):
|
|||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Initialize Escrow contract
|
||||
tx = escrow.functions.initialize().transact({'from': creator})
|
||||
tx = escrow.functions.initialize(0).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Ursula can't deposit and lock too low value (less than _minAllowableLockedTokens coefficient)
|
||||
|
@ -550,7 +550,7 @@ def test_max_sub_stakes(testerchain, token, escrow_contract):
|
|||
ursula = testerchain.client.accounts[1]
|
||||
|
||||
# Initialize Escrow contract
|
||||
tx = escrow.functions.initialize().transact({'from': creator})
|
||||
tx = escrow.functions.initialize(0).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Prepare before deposit
|
||||
|
|
|
@ -42,7 +42,7 @@ def test_upgrading(testerchain, token, token_economics, deploy_contract):
|
|||
|
||||
# Deploy contract
|
||||
contract_library_v1, _ = deploy_contract(
|
||||
'StakingEscrow', token.address, *token_economics.staking_deployment_parameters
|
||||
'StakingEscrow', token.address, *token_economics.staking_deployment_parameters, True
|
||||
)
|
||||
dispatcher, _ = deploy_contract('Dispatcher', contract_library_v1.address, secret_hash)
|
||||
|
||||
|
@ -58,6 +58,7 @@ def test_upgrading(testerchain, token, token_economics, deploy_contract):
|
|||
_minAllowableLockedTokens=2,
|
||||
_maxAllowableLockedTokens=2,
|
||||
_minWorkerPeriods=2,
|
||||
_isTestContract=False,
|
||||
_valueToCheck=2
|
||||
)
|
||||
|
||||
|
@ -66,6 +67,7 @@ def test_upgrading(testerchain, token, token_economics, deploy_contract):
|
|||
address=dispatcher.address,
|
||||
ContractFactoryClass=Contract)
|
||||
assert token_economics.maximum_allowed_locked == contract.functions.maxAllowableLockedTokens().call()
|
||||
assert contract.functions.isTestContract().call()
|
||||
|
||||
# Can't call `finishUpgrade` and `verifyState` methods outside upgrade lifecycle
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
|
@ -94,9 +96,9 @@ def test_upgrading(testerchain, token, token_economics, deploy_contract):
|
|||
tx = contract.functions.setWorkLock(worklock.address).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
tx = token.functions.transfer(contract.address, token_economics.erc20_reward_supply).transact({'from': creator})
|
||||
tx = token.functions.approve(contract.address, token_economics.erc20_reward_supply).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = contract.functions.initialize().transact({'from': creator})
|
||||
tx = contract.functions.initialize(token_economics.erc20_reward_supply).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = token.functions.transfer(staker, 1000).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
@ -119,6 +121,10 @@ def test_upgrading(testerchain, token, token_economics, deploy_contract):
|
|||
tx = contract.functions.confirmActivity().transact({'from': worker})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Can set WorkLock twice, because isTestContract == True
|
||||
tx = contract.functions.setWorkLock(worklock.address).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Upgrade to the second version
|
||||
tx = dispatcher.functions.upgrade(contract_library_v2.address, secret, secret2_hash).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
@ -127,6 +133,10 @@ def test_upgrading(testerchain, token, token_economics, deploy_contract):
|
|||
assert token_economics.maximum_allowed_locked == contract.functions.maxAllowableLockedTokens().call()
|
||||
assert policy_manager.address == contract.functions.policyManager().call()
|
||||
assert 2 == contract.functions.valueToCheck().call()
|
||||
assert not contract.functions.isTestContract().call()
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = contract.functions.setWorkLock(worklock.address).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
# Check new ABI
|
||||
tx = contract.functions.setValueToCheck(3).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
@ -143,7 +153,8 @@ def test_upgrading(testerchain, token, token_economics, deploy_contract):
|
|||
_minLockedPeriods=2,
|
||||
_minAllowableLockedTokens=2,
|
||||
_maxAllowableLockedTokens=2,
|
||||
_minWorkerPeriods=2
|
||||
_minWorkerPeriods=2,
|
||||
_isTestContract=False
|
||||
)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = dispatcher.functions.upgrade(contract_library_v1.address, secret2, secret_hash)\
|
||||
|
@ -159,6 +170,9 @@ def test_upgrading(testerchain, token, token_economics, deploy_contract):
|
|||
testerchain.wait_for_receipt(tx)
|
||||
assert contract_library_v1.address == dispatcher.functions.target().call()
|
||||
assert policy_manager.address == contract.functions.policyManager().call()
|
||||
assert contract.functions.isTestContract().call()
|
||||
tx = contract.functions.setWorkLock(worklock.address).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
# After rollback new ABI is unavailable
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = contract.functions.setValueToCheck(2).transact({'from': creator})
|
||||
|
@ -207,9 +221,10 @@ def test_re_stake(testerchain, token, escrow_contract):
|
|||
re_stake_lock_log = escrow.events.ReStakeLocked.createFilter(fromBlock='latest')
|
||||
|
||||
# Give Escrow tokens for reward and initialize contract
|
||||
tx = token.functions.transfer(escrow.address, 10 ** 9).transact({'from': creator})
|
||||
reward = 10 ** 9
|
||||
tx = token.functions.approve(escrow.address, reward).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = escrow.functions.initialize().transact({'from': creator})
|
||||
tx = escrow.functions.initialize(reward).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Set re-stake parameter even before initialization
|
||||
|
@ -469,7 +484,7 @@ def test_worker(testerchain, token, escrow_contract, deploy_contract):
|
|||
worker_log = escrow.events.WorkerSet.createFilter(fromBlock='latest')
|
||||
|
||||
# Initialize escrow contract
|
||||
tx = escrow.functions.initialize().transact({'from': creator})
|
||||
tx = escrow.functions.initialize(0).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Deploy intermediary contracts
|
||||
|
@ -710,9 +725,10 @@ def test_measure_work(testerchain, token, escrow_contract, deploy_contract):
|
|||
work_measurement_log = escrow.events.WorkMeasurementSet.createFilter(fromBlock='latest')
|
||||
|
||||
# Initialize escrow contract
|
||||
tx = token.functions.transfer(escrow.address, int(NU(10 ** 9, 'NuNit'))).transact({'from': creator})
|
||||
reward = 10 ** 9
|
||||
tx = token.functions.approve(escrow.address, int(NU(reward, 'NuNit'))).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = escrow.functions.initialize().transact({'from': creator})
|
||||
tx = escrow.functions.initialize(reward).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Deploy WorkLock mock
|
||||
|
|
|
@ -14,9 +14,13 @@ GNU Affero General Public License for more details.
|
|||
You should have received a copy of the GNU Affero General Public License
|
||||
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
import os
|
||||
|
||||
import pytest
|
||||
import rlp
|
||||
from eth_tester.exceptions import TransactionFailed
|
||||
from eth_utils import to_wei, keccak, to_canonical_address, to_checksum_address
|
||||
from web3.contract import Contract
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
|
@ -25,6 +29,22 @@ def token(testerchain, token_economics, deploy_contract):
|
|||
return contract
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def router(testerchain, deploy_contract):
|
||||
staking_interface, _ = deploy_contract('StakingInterfaceMock')
|
||||
secret = os.urandom(32)
|
||||
secret_hash = keccak(secret)
|
||||
contract, _ = deploy_contract('StakingInterfaceRouter', staking_interface.address, secret_hash)
|
||||
return contract
|
||||
|
||||
|
||||
def next_address(testerchain, worklock):
|
||||
# https://github.com/ethereum/wiki/wiki/Subtleties#nonces
|
||||
nonce = testerchain.w3.eth.getTransactionCount(worklock.address)
|
||||
data_to_encode = [to_canonical_address(worklock.address), nonce]
|
||||
return to_checksum_address(keccak(rlp.codec.encode(data_to_encode))[12:])
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def escrow(testerchain, token_economics, deploy_contract, token):
|
||||
contract, _ = deploy_contract(
|
||||
|
@ -38,306 +58,462 @@ def escrow(testerchain, token_economics, deploy_contract, token):
|
|||
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_worklock(testerchain, token_economics, deploy_contract, token, escrow):
|
||||
creator, ursula1, ursula2, *everyone_else = testerchain.w3.eth.accounts
|
||||
def test_worklock(testerchain, token_economics, deploy_contract, token, escrow, router):
|
||||
creator, staker1, staker2, staker3, *everyone_else = testerchain.w3.eth.accounts
|
||||
|
||||
# Deploy fake preallocation escrow
|
||||
preallocation_escrow_fake, _ = deploy_contract('PreallocationEscrow', router.address, token.address, escrow.address)
|
||||
tx = preallocation_escrow_fake.functions.transferOwnership(staker1).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Deploy WorkLock
|
||||
now = testerchain.w3.eth.getBlock(block_identifier='latest').timestamp
|
||||
start_bid_date = now + (60 * 60) # 1 Hour
|
||||
end_bid_date = start_bid_date + (60 * 60)
|
||||
deposit_rate = 100
|
||||
refund_rate = 200
|
||||
boosting_refund = 50
|
||||
slowing_refund = 100
|
||||
locking_duration = 60 * 60
|
||||
worklock, _ = deploy_contract(
|
||||
contract_name='WorkLock',
|
||||
_token=token.address,
|
||||
_escrow=escrow.address,
|
||||
_router=router.address,
|
||||
_startBidDate=start_bid_date,
|
||||
_endBidDate=end_bid_date,
|
||||
_depositRate=deposit_rate,
|
||||
_refundRate=refund_rate,
|
||||
_lockedPeriods=2 * token_economics.minimum_locked_periods
|
||||
_boostingRefund=boosting_refund,
|
||||
_lockingDuration=locking_duration
|
||||
)
|
||||
assert worklock.functions.startBidDate().call() == start_bid_date
|
||||
assert worklock.functions.endBidDate().call() == end_bid_date
|
||||
assert worklock.functions.minAllowableLockedTokens().call() == token_economics.minimum_allowed_locked
|
||||
assert worklock.functions.maxAllowableLockedTokens().call() == token_economics.maximum_allowed_locked
|
||||
assert worklock.functions.depositRate().call() == deposit_rate
|
||||
assert worklock.functions.refundRate().call() == refund_rate
|
||||
assert worklock.functions.boostingRefund().call() == boosting_refund
|
||||
assert worklock.functions.SLOWING_REFUND().call() == slowing_refund
|
||||
assert worklock.functions.lockingDuration().call() == locking_duration
|
||||
|
||||
deposit_log = worklock.events.Deposited.createFilter(fromBlock='latest')
|
||||
bidding_log = worklock.events.Bid.createFilter(fromBlock='latest')
|
||||
claim_log = worklock.events.Claimed.createFilter(fromBlock='latest')
|
||||
refund_log = worklock.events.Refund.createFilter(fromBlock='latest')
|
||||
burning_log = worklock.events.Burnt.createFilter(fromBlock='latest')
|
||||
canceling_log = worklock.events.Canceled.createFilter(fromBlock='latest')
|
||||
|
||||
# Transfer tokens to WorkLock
|
||||
worklock_supply = 2 * token_economics.maximum_allowed_locked - 1
|
||||
tx = token.functions.transfer(worklock.address, worklock_supply).transact({'from': creator})
|
||||
worklock_supply_1 = 2 * token_economics.maximum_allowed_locked + 1
|
||||
worklock_supply_2 = token_economics.maximum_allowed_locked - 1
|
||||
worklock_supply = worklock_supply_1 + worklock_supply_2
|
||||
tx = token.functions.approve(worklock.address, worklock_supply).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = worklock.functions.tokenDeposit(worklock_supply_1).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.tokenSupply().call() == worklock_supply_1
|
||||
tx = worklock.functions.tokenDeposit(worklock_supply_2).transact({'from': creator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.tokenSupply().call() == worklock_supply
|
||||
|
||||
events = deposit_log.get_all_entries()
|
||||
assert 2 == len(events)
|
||||
event_args = events[0]['args']
|
||||
assert event_args['sender'] == creator
|
||||
assert event_args['value'] == worklock_supply_1
|
||||
event_args = events[1]['args']
|
||||
assert event_args['sender'] == creator
|
||||
assert event_args['value'] == worklock_supply_2
|
||||
|
||||
# Give Ursulas some ETH
|
||||
minimum_deposit_eth = token_economics.minimum_allowed_locked // deposit_rate
|
||||
maximum_deposit_eth = token_economics.maximum_allowed_locked // deposit_rate
|
||||
ursula1_balance = 2 * maximum_deposit_eth
|
||||
deposit_eth_1 = to_wei(4, 'ether')
|
||||
deposit_eth_2 = deposit_eth_1 // 4
|
||||
staker1_balance = 10 * deposit_eth_1
|
||||
tx = testerchain.w3.eth.sendTransaction(
|
||||
{'from': testerchain.etherbase_account, 'to': ursula1, 'value': ursula1_balance})
|
||||
{'from': testerchain.etherbase_account, 'to': staker1, 'value': staker1_balance})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
ursula2_balance = 2 * maximum_deposit_eth
|
||||
ursula2_balance = staker1_balance
|
||||
tx = testerchain.w3.eth.sendTransaction(
|
||||
{'from': testerchain.etherbase_account, 'to': ursula2, 'value': ursula2_balance})
|
||||
{'from': testerchain.etherbase_account, 'to': staker2, 'value': ursula2_balance})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
staker3_balance = staker1_balance
|
||||
tx = testerchain.w3.eth.sendTransaction(
|
||||
{'from': testerchain.etherbase_account, 'to': staker3, 'value': staker3_balance})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Can't do anything before start date
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.bid().transact({'from': ursula1, 'value': minimum_deposit_eth, 'gas_price': 0})
|
||||
tx = worklock.functions.bid().transact({'from': staker1, 'value': deposit_eth_1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.claim().transact({'from': ursula1, 'gas_price': 0})
|
||||
tx = worklock.functions.claim().transact({'from': staker1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.refund().transact({'from': ursula1, 'gas_price': 0})
|
||||
tx = worklock.functions.refund(preallocation_escrow_fake.address).transact({'from': staker1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.burnUnclaimed().transact({'from': staker1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.cancelBid().transact({'from': staker1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Wait for the start of bidding
|
||||
testerchain.time_travel(seconds=3600) # Wait exactly 1 hour
|
||||
|
||||
# Can't bid with too low or too high ETH
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.bid().transact({'from': ursula1, 'value': minimum_deposit_eth - 1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.bid().transact({'from': ursula1, 'value': maximum_deposit_eth + 1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Ursula does first bid
|
||||
assert worklock.functions.allClaimedTokens().call() == 0
|
||||
assert worklock.functions.workInfo(ursula1).call()[0] == 0
|
||||
assert worklock.functions.workInfo(staker1).call()[0] == 0
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == 0
|
||||
tx = worklock.functions.bid().transact({'from': ursula1, 'value': minimum_deposit_eth, 'gas_price': 0})
|
||||
tx = worklock.functions.bid().transact({'from': staker1, 'value': deposit_eth_1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.allClaimedTokens().call() == token_economics.minimum_allowed_locked
|
||||
assert worklock.functions.workInfo(ursula1).call()[0] == minimum_deposit_eth
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == minimum_deposit_eth
|
||||
assert worklock.functions.workInfo(staker1).call()[0] == deposit_eth_1
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == deposit_eth_1
|
||||
assert worklock.functions.ethToTokens(deposit_eth_1).call() == worklock_supply
|
||||
|
||||
events = bidding_log.get_all_entries()
|
||||
assert 1 == len(events)
|
||||
event_args = events[0]['args']
|
||||
assert event_args['staker'] == ursula1
|
||||
assert event_args['depositedETH'] == minimum_deposit_eth
|
||||
assert event_args['claimedTokens'] == token_economics.minimum_allowed_locked
|
||||
assert event_args['sender'] == staker1
|
||||
assert event_args['depositedETH'] == deposit_eth_1
|
||||
|
||||
# Second Ursula does first bid
|
||||
assert worklock.functions.workInfo(ursula2).call()[0] == 0
|
||||
tx = worklock.functions.bid().transact({'from': ursula2, 'value': maximum_deposit_eth, 'gas_price': 0})
|
||||
assert worklock.functions.workInfo(staker2).call()[0] == 0
|
||||
tx = worklock.functions.bid().transact({'from': staker2, 'value': deposit_eth_2, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.allClaimedTokens().call() == \
|
||||
token_economics.minimum_allowed_locked + token_economics.maximum_allowed_locked
|
||||
assert worklock.functions.workInfo(ursula2).call()[0] == maximum_deposit_eth
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == maximum_deposit_eth + minimum_deposit_eth
|
||||
assert worklock.functions.workInfo(staker2).call()[0] == deposit_eth_2
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == deposit_eth_1 + deposit_eth_2
|
||||
assert worklock.functions.ethToTokens(deposit_eth_2).call() == worklock_supply // 5
|
||||
|
||||
events = bidding_log.get_all_entries()
|
||||
assert 2 == len(events)
|
||||
event_args = events[1]['args']
|
||||
assert event_args['staker'] == ursula2
|
||||
assert event_args['depositedETH'] == maximum_deposit_eth
|
||||
assert event_args['claimedTokens'] == token_economics.maximum_allowed_locked
|
||||
assert event_args['sender'] == staker2
|
||||
assert event_args['depositedETH'] == deposit_eth_2
|
||||
|
||||
# Can't bid again with too high ETH
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.bid().transact(
|
||||
{'from': ursula1, 'value': maximum_deposit_eth-minimum_deposit_eth+1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.bid().transact({'from': ursula2, 'value': 1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Ursula does second bid
|
||||
tx = worklock.functions.bid().transact({'from': ursula1, 'value': minimum_deposit_eth, 'gas_price': 0})
|
||||
# Third Ursula does first bid
|
||||
assert worklock.functions.workInfo(staker3).call()[0] == 0
|
||||
tx = worklock.functions.bid().transact({'from': staker3, 'value': deposit_eth_2, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.allClaimedTokens().call() == \
|
||||
2 * token_economics.minimum_allowed_locked + token_economics.maximum_allowed_locked
|
||||
assert worklock.functions.workInfo(ursula1).call()[0] == 2 * minimum_deposit_eth
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == maximum_deposit_eth + 2 * minimum_deposit_eth
|
||||
assert worklock.functions.workInfo(staker3).call()[0] == deposit_eth_2
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == deposit_eth_1 + 2 * deposit_eth_2
|
||||
assert worklock.functions.ethToTokens(deposit_eth_2).call() == worklock_supply // 6
|
||||
|
||||
events = bidding_log.get_all_entries()
|
||||
assert 3 == len(events)
|
||||
event_args = events[2]['args']
|
||||
assert event_args['staker'] == ursula1
|
||||
assert event_args['depositedETH'] == minimum_deposit_eth
|
||||
assert event_args['claimedTokens'] == token_economics.minimum_allowed_locked
|
||||
assert event_args['sender'] == staker3
|
||||
assert event_args['depositedETH'] == deposit_eth_2
|
||||
|
||||
# Can't bid again: not enough tokens in worklock
|
||||
# Ursula does second bid
|
||||
tx = worklock.functions.bid().transact({'from': staker1, 'value': deposit_eth_1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.workInfo(staker1).call()[0] == 2 * deposit_eth_1
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == 2 * deposit_eth_1 + 2 * deposit_eth_2
|
||||
assert worklock.functions.ethToTokens(deposit_eth_2).call() == worklock_supply // 10
|
||||
|
||||
events = bidding_log.get_all_entries()
|
||||
assert 4 == len(events)
|
||||
event_args = events[3]['args']
|
||||
assert event_args['sender'] == staker1
|
||||
assert event_args['depositedETH'] == deposit_eth_1
|
||||
|
||||
# Can't claim, refund or burn while bidding phase
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.bid().transact(
|
||||
{'from': ursula1, 'value': maximum_deposit_eth - 2 * minimum_deposit_eth, 'gas_price': 0})
|
||||
tx = worklock.functions.claim().transact({'from': staker1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.refund(preallocation_escrow_fake.address).transact({'from': staker1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.burnUnclaimed().transact({'from': staker1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Can't claim or refund while bidding phase
|
||||
# But can cancel bid
|
||||
staker3_balance = testerchain.w3.eth.getBalance(staker3)
|
||||
tx = worklock.functions.cancelBid().transact({'from': staker3, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.workInfo(staker3).call()[0] == 0
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == 2 * deposit_eth_1 + deposit_eth_2
|
||||
assert worklock.functions.ethToTokens(deposit_eth_2).call() == worklock_supply // 9
|
||||
assert testerchain.w3.eth.getBalance(staker3) == staker3_balance + deposit_eth_2
|
||||
|
||||
events = canceling_log.get_all_entries()
|
||||
assert 1 == len(events)
|
||||
event_args = events[0]['args']
|
||||
assert event_args['sender'] == staker3
|
||||
assert event_args['value'] == deposit_eth_2
|
||||
|
||||
# Can't cancel twice in a row
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.claim().transact({'from': ursula1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.refund().transact({'from': ursula1, 'gas_price': 0})
|
||||
tx = worklock.functions.cancelBid().transact({'from': staker3, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Third Ursula does second bid
|
||||
assert worklock.functions.workInfo(staker3).call()[0] == 0
|
||||
tx = worklock.functions.bid().transact({'from': staker3, 'value': deposit_eth_2, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.workInfo(staker3).call()[0] == deposit_eth_2
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == 2 * deposit_eth_1 + 2 * deposit_eth_2
|
||||
assert worklock.functions.ethToTokens(deposit_eth_2).call() == worklock_supply // 10
|
||||
|
||||
events = bidding_log.get_all_entries()
|
||||
assert 5 == len(events)
|
||||
event_args = events[4]['args']
|
||||
assert event_args['sender'] == staker3
|
||||
assert event_args['depositedETH'] == deposit_eth_2
|
||||
|
||||
# Wait for the end of bidding
|
||||
testerchain.time_travel(seconds=3600) # Wait exactly 1 hour
|
||||
|
||||
# Can't bid after the enf of bidding
|
||||
# Can't bid after the end of bidding
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.bid().transact({'from': ursula1, 'value': minimum_deposit_eth, 'gas_price': 0})
|
||||
tx = worklock.functions.bid().transact({'from': staker1, 'value': deposit_eth_1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Can't refund without claim
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.refund().transact({'from': ursula1, 'gas_price': 0})
|
||||
tx = worklock.functions.refund(preallocation_escrow_fake.address).transact({'from': staker1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Ursula claims tokens
|
||||
value, measure_work, _completed_work, periods = escrow.functions.stakerInfo(ursula1).call()
|
||||
assert value == 0
|
||||
preallocation_escrow_1_address = next_address(testerchain, worklock)
|
||||
_value, measure_work, _completed_work, _periods = escrow.functions.stakerInfo(preallocation_escrow_1_address).call()
|
||||
assert not measure_work
|
||||
assert periods == 0
|
||||
tx = worklock.functions.claim().transact({'from': ursula1, 'gas_price': 0})
|
||||
tx = worklock.functions.claim().transact({'from': staker1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.getRemainingWork(ursula1).call() == 2 * minimum_deposit_eth * refund_rate
|
||||
value, measure_work, completed_work, periods = escrow.functions.stakerInfo(ursula1).call()
|
||||
assert value == 2 * token_economics.minimum_allowed_locked
|
||||
staker1_tokens = 8 * worklock_supply // 10
|
||||
preallocation_escrow_1 = testerchain.client.get_contract(
|
||||
abi=preallocation_escrow_fake.abi,
|
||||
address=worklock.functions.workInfo(staker1).call()[2],
|
||||
ContractFactoryClass=Contract)
|
||||
assert preallocation_escrow_1.address == preallocation_escrow_1_address
|
||||
assert token.functions.balanceOf(staker1).call() == 0
|
||||
assert token.functions.balanceOf(preallocation_escrow_1.address).call() == staker1_tokens
|
||||
assert preallocation_escrow_1.functions.owner().call() == staker1
|
||||
assert preallocation_escrow_1.functions.router().call() == router.address
|
||||
assert preallocation_escrow_1.functions.lockedValue().call() == staker1_tokens
|
||||
assert preallocation_escrow_1.functions.getLockedTokens().call() == staker1_tokens
|
||||
assert preallocation_escrow_1.functions.endLockTimestamp().call() == \
|
||||
testerchain.w3.eth.getBlock(block_identifier='latest').timestamp + locking_duration
|
||||
staker1_remaining_work = int(-(-8 * worklock_supply * slowing_refund // (boosting_refund * 10))) # div ceil
|
||||
assert worklock.functions.ethToWork(2 * deposit_eth_1).call() == staker1_remaining_work
|
||||
assert worklock.functions.workToETH(staker1_remaining_work).call() == 2 * deposit_eth_1
|
||||
assert worklock.functions.getRemainingWork(preallocation_escrow_1_address).call() == staker1_remaining_work
|
||||
assert token.functions.balanceOf(worklock.address).call() == worklock_supply - staker1_tokens
|
||||
_value, measure_work, _completed_work, _periods = escrow.functions.stakerInfo(preallocation_escrow_1_address).call()
|
||||
assert measure_work
|
||||
assert periods == 2 * token_economics.minimum_locked_periods
|
||||
assert token.functions.balanceOf(worklock.address).call() == \
|
||||
worklock_supply - 2 * token_economics.minimum_allowed_locked
|
||||
assert token.functions.balanceOf(escrow.address).call() == 2 * token_economics.minimum_allowed_locked
|
||||
|
||||
events = claim_log.get_all_entries()
|
||||
assert 1 == len(events)
|
||||
event_args = events[0]['args']
|
||||
assert event_args['staker'] == ursula1
|
||||
assert event_args['claimedTokens'] == 2 * token_economics.minimum_allowed_locked
|
||||
assert event_args['sender'] == staker1
|
||||
assert event_args['claimedTokens'] == staker1_tokens
|
||||
assert event_args['preallocationEscrow'] == preallocation_escrow_1_address
|
||||
|
||||
# Can't claim more than once
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.claim().transact({'from': ursula1, 'gas_price': 0})
|
||||
tx = worklock.functions.claim().transact({'from': staker1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Can't refund without work
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.refund().transact({'from': ursula1, 'gas_price': 0})
|
||||
tx = worklock.functions.refund(preallocation_escrow_1.address).transact({'from': staker1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
# Can't cancel after claim
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.cancelBid().transact({'from': staker1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# One of Ursulas cancel bid
|
||||
staker3_balance = testerchain.w3.eth.getBalance(staker3)
|
||||
staker3_tokens = worklock_supply // 10
|
||||
assert worklock.functions.ethToTokens(deposit_eth_2).call() == staker3_tokens
|
||||
tx = worklock.functions.cancelBid().transact({'from': staker3, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.ethToTokens(deposit_eth_2).call() == staker3_tokens
|
||||
assert worklock.functions.workInfo(staker3).call()[0] == 0
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == 2 * deposit_eth_1 + deposit_eth_2
|
||||
assert testerchain.w3.eth.getBalance(staker3) == staker3_balance + deposit_eth_2
|
||||
assert worklock.functions.unclaimedTokens().call() == staker3_tokens
|
||||
assert token.functions.balanceOf(worklock.address).call() == worklock_supply - staker1_tokens
|
||||
|
||||
# Second Ursula claims tokens
|
||||
value, measure_work, _completed_work, periods = escrow.functions.stakerInfo(ursula2).call()
|
||||
assert value == 0
|
||||
preallocation_escrow_2_address = next_address(testerchain, worklock)
|
||||
_value, measure_work, _completed_work, _periods = escrow.functions.stakerInfo(preallocation_escrow_2_address).call()
|
||||
assert not measure_work
|
||||
assert periods == 0
|
||||
tx = escrow.functions.setCompletedWork(ursula2, refund_rate * minimum_deposit_eth).transact()
|
||||
staker2_tokens = staker3_tokens
|
||||
# staker2_tokens * slowing_refund / boosting_refund
|
||||
staker2_remaining_work = int(-(-worklock_supply * slowing_refund // (boosting_refund * 10))) # div ceil
|
||||
assert worklock.functions.ethToWork(deposit_eth_2).call() == staker2_remaining_work
|
||||
assert worklock.functions.workToETH(staker2_remaining_work).call() == deposit_eth_2
|
||||
tx = escrow.functions.setCompletedWork(preallocation_escrow_2_address, staker2_remaining_work // 2).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = worklock.functions.claim().transact({'from': ursula2, 'gas_price': 0})
|
||||
tx = worklock.functions.claim().transact({'from': staker2, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.getRemainingWork(ursula2).call() == maximum_deposit_eth * refund_rate
|
||||
value, measure_work, completed_work, periods = escrow.functions.stakerInfo(ursula2).call()
|
||||
assert value == token_economics.maximum_allowed_locked
|
||||
assert worklock.functions.getRemainingWork(preallocation_escrow_2_address).call() == staker2_remaining_work
|
||||
assert token.functions.balanceOf(worklock.address).call() == worklock_supply - staker1_tokens - staker2_tokens
|
||||
assert token.functions.balanceOf(staker2).call() == 0
|
||||
preallocation_escrow_2 = testerchain.client.get_contract(
|
||||
abi=preallocation_escrow_fake.abi,
|
||||
address=worklock.functions.workInfo(staker2).call()[2],
|
||||
ContractFactoryClass=Contract)
|
||||
assert preallocation_escrow_2.address == preallocation_escrow_2_address
|
||||
assert token.functions.balanceOf(preallocation_escrow_2.address).call() == staker2_tokens
|
||||
assert preallocation_escrow_2.functions.owner().call() == staker2
|
||||
assert preallocation_escrow_2.functions.getLockedTokens().call() == staker2_tokens
|
||||
_value, measure_work, _completed_work, _periods = escrow.functions.stakerInfo(preallocation_escrow_2.address).call()
|
||||
assert measure_work
|
||||
assert periods == 2 * token_economics.minimum_locked_periods
|
||||
assert token.functions.balanceOf(worklock.address).call() == \
|
||||
worklock_supply - 2 * token_economics.minimum_allowed_locked - token_economics.maximum_allowed_locked
|
||||
assert token.functions.balanceOf(escrow.address).call() == \
|
||||
2 * token_economics.minimum_allowed_locked + token_economics.maximum_allowed_locked
|
||||
|
||||
events = claim_log.get_all_entries()
|
||||
assert 2 == len(events)
|
||||
event_args = events[1]['args']
|
||||
assert event_args['staker'] == ursula2
|
||||
assert event_args['claimedTokens'] == token_economics.maximum_allowed_locked
|
||||
assert event_args['sender'] == staker2
|
||||
assert event_args['claimedTokens'] == staker2_tokens
|
||||
assert event_args['preallocationEscrow'] == preallocation_escrow_2_address
|
||||
|
||||
# "Do" some work and partial refund
|
||||
ursula1_balance = testerchain.w3.eth.getBalance(ursula1)
|
||||
completed_work = refund_rate * minimum_deposit_eth + refund_rate // 2
|
||||
tx = escrow.functions.setCompletedWork(ursula1, completed_work).transact()
|
||||
staker1_balance = testerchain.w3.eth.getBalance(staker1)
|
||||
completed_work = staker1_remaining_work // 2 + 1
|
||||
remaining_work = staker1_remaining_work - completed_work
|
||||
tx = escrow.functions.setCompletedWork(preallocation_escrow_1_address, completed_work).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.getRemainingWork(ursula1).call() == minimum_deposit_eth * refund_rate - refund_rate // 2
|
||||
tx = worklock.functions.refund().transact({'from': ursula1, 'gas_price': 0})
|
||||
assert worklock.functions.getRemainingWork(preallocation_escrow_1_address).call() == remaining_work
|
||||
|
||||
# Can't refund using wrong escrow address
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.refund(preallocation_escrow_fake.address).transact({'from': staker1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
# Only owner of escrow can call refund
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.refund(preallocation_escrow_1_address).transact({'from': staker2, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
tx = worklock.functions.refund(preallocation_escrow_1_address).transact({'from': staker1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.workInfo(ursula1).call()[0] == minimum_deposit_eth
|
||||
assert worklock.functions.getRemainingWork(ursula1).call() == minimum_deposit_eth * refund_rate - refund_rate // 2
|
||||
assert testerchain.w3.eth.getBalance(ursula1) == ursula1_balance + minimum_deposit_eth
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == maximum_deposit_eth + minimum_deposit_eth
|
||||
_value, measure_work, _completed_work, _periods = escrow.functions.stakerInfo(ursula1).call()
|
||||
assert worklock.functions.workInfo(staker1).call()[0] == deposit_eth_1
|
||||
assert worklock.functions.getRemainingWork(preallocation_escrow_1_address).call() == remaining_work
|
||||
assert testerchain.w3.eth.getBalance(staker1) == staker1_balance + deposit_eth_1
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == deposit_eth_1 + deposit_eth_2
|
||||
_value, measure_work, _completed_work, _periods = escrow.functions.stakerInfo(preallocation_escrow_1_address).call()
|
||||
assert measure_work
|
||||
|
||||
events = refund_log.get_all_entries()
|
||||
assert 1 == len(events)
|
||||
event_args = events[0]['args']
|
||||
assert event_args['staker'] == ursula1
|
||||
assert event_args['refundETH'] == minimum_deposit_eth
|
||||
assert event_args['completedWork'] == minimum_deposit_eth * refund_rate
|
||||
assert event_args['sender'] == staker1
|
||||
assert event_args['preallocationEscrow'] == preallocation_escrow_1_address
|
||||
assert event_args['refundETH'] == deposit_eth_1
|
||||
assert event_args['completedWork'] == staker1_remaining_work // 2
|
||||
|
||||
# Transfer ownership of preallocation escrow to the new staker
|
||||
tx = preallocation_escrow_1.functions.transferOwnership(staker2).transact({'from': staker1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# "Do" more work and full refund
|
||||
ursula1_balance = testerchain.w3.eth.getBalance(ursula1)
|
||||
completed_work = refund_rate * 2 * minimum_deposit_eth
|
||||
tx = escrow.functions.setCompletedWork(ursula1, completed_work).transact()
|
||||
staker1_balance = testerchain.w3.eth.getBalance(staker1)
|
||||
staker2_balance = testerchain.w3.eth.getBalance(staker2)
|
||||
completed_work = staker1_remaining_work
|
||||
tx = escrow.functions.setCompletedWork(preallocation_escrow_1_address, completed_work).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.getRemainingWork(ursula1).call() == 0
|
||||
tx = worklock.functions.refund().transact({'from': ursula1, 'gas_price': 0})
|
||||
assert worklock.functions.getRemainingWork(preallocation_escrow_1_address).call() == 0
|
||||
|
||||
# Only ??? owner of escrow can call refund
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.refund(preallocation_escrow_1_address).transact({'from': staker1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
tx = worklock.functions.refund(preallocation_escrow_1_address).transact({'from': staker2, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.workInfo(ursula1).call()[0] == 0
|
||||
assert worklock.functions.getRemainingWork(ursula1).call() == 0
|
||||
assert testerchain.w3.eth.getBalance(ursula1) == ursula1_balance + minimum_deposit_eth
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == maximum_deposit_eth
|
||||
_value, measure_work, _completed_work, _periods = escrow.functions.stakerInfo(ursula1).call()
|
||||
assert worklock.functions.workInfo(staker1).call()[0] == 0
|
||||
assert worklock.functions.workInfo(staker2).call()[0] == deposit_eth_2
|
||||
assert worklock.functions.getRemainingWork(preallocation_escrow_1_address).call() == 0
|
||||
assert testerchain.w3.eth.getBalance(staker2) == staker2_balance + deposit_eth_1
|
||||
assert testerchain.w3.eth.getBalance(staker1) == staker1_balance
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == deposit_eth_2
|
||||
_value, measure_work, _completed_work, _periods = escrow.functions.stakerInfo(preallocation_escrow_1_address).call()
|
||||
assert not measure_work
|
||||
|
||||
events = refund_log.get_all_entries()
|
||||
assert 2 == len(events)
|
||||
event_args = events[1]['args']
|
||||
assert event_args['staker'] == ursula1
|
||||
assert event_args['refundETH'] == minimum_deposit_eth
|
||||
assert event_args['completedWork'] == minimum_deposit_eth * refund_rate
|
||||
assert event_args['sender'] == staker2
|
||||
assert event_args['preallocationEscrow'] == preallocation_escrow_1_address
|
||||
assert event_args['refundETH'] == deposit_eth_1
|
||||
assert event_args['completedWork'] == staker1_remaining_work // 2
|
||||
|
||||
# Can't refund more tokens
|
||||
tx = escrow.functions.setCompletedWork(ursula1, 2 * completed_work).transact()
|
||||
tx = escrow.functions.setCompletedWork(staker1, 2 * completed_work).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.refund().transact({'from': ursula1, 'gas_price': 0})
|
||||
tx = worklock.functions.refund(preallocation_escrow_1_address).transact({'from': staker2, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Now burn remaining tokens
|
||||
assert worklock.functions.unclaimedTokens().call() == staker3_tokens
|
||||
tx = worklock.functions.burnUnclaimed().transact({'from': staker1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.unclaimedTokens().call() == 0
|
||||
assert token.functions.balanceOf(worklock.address).call() == 0
|
||||
assert token.functions.balanceOf(escrow.address).call() == staker3_tokens
|
||||
|
||||
# Can't burn twice
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.burnUnclaimed().transact({'from': staker1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
events = burning_log.get_all_entries()
|
||||
assert 1 == len(events)
|
||||
event_args = events[0]['args']
|
||||
assert event_args['sender'] == staker1
|
||||
assert event_args['value'] == staker3_tokens
|
||||
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_reentrancy(testerchain, token_economics, deploy_contract, token, escrow):
|
||||
def test_reentrancy(testerchain, token_economics, deploy_contract, token, escrow, router):
|
||||
# Deploy WorkLock
|
||||
now = testerchain.w3.eth.getBlock(block_identifier='latest').timestamp
|
||||
start_bid_date = now
|
||||
end_bid_date = start_bid_date + (60 * 60)
|
||||
deposit_rate = 1
|
||||
refund_rate = 1
|
||||
boosting_refund = 100
|
||||
locking_duration = 60 * 60
|
||||
worklock, _ = deploy_contract(
|
||||
contract_name='WorkLock',
|
||||
_token=token.address,
|
||||
_escrow=escrow.address,
|
||||
_router=router.address,
|
||||
_startBidDate=start_bid_date,
|
||||
_endBidDate=end_bid_date,
|
||||
_depositRate=deposit_rate,
|
||||
_refundRate=refund_rate,
|
||||
_lockedPeriods=2 * token_economics.minimum_locked_periods
|
||||
_boostingRefund=boosting_refund,
|
||||
_lockingDuration=locking_duration
|
||||
)
|
||||
refund_log = worklock.events.Refund.createFilter(fromBlock='latest')
|
||||
worklock_supply = 2 * token_economics.maximum_allowed_locked - 1
|
||||
tx = token.functions.transfer(worklock.address, worklock_supply).transact()
|
||||
canceling_log = worklock.events.Canceled.createFilter(fromBlock='latest')
|
||||
worklock_supply = 3 * token_economics.maximum_allowed_locked
|
||||
tx = token.functions.approve(worklock.address, worklock_supply).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = worklock.functions.tokenDeposit(worklock_supply).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
reentrancy_contract, _ = deploy_contract('ReentrancyTest')
|
||||
contract_address = reentrancy_contract.address
|
||||
minimum_deposit_eth = token_economics.minimum_allowed_locked // deposit_rate
|
||||
deposit_eth = to_wei(3, 'ether')
|
||||
tx = testerchain.client.send_transaction(
|
||||
{'from': testerchain.etherbase_account, 'to': contract_address, 'value': minimum_deposit_eth})
|
||||
{'from': testerchain.etherbase_account, 'to': contract_address, 'value': deposit_eth})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Bid
|
||||
transaction = worklock.functions.bid().buildTransaction({'gas': 0})
|
||||
tx = reentrancy_contract.functions.setData(1, transaction['to'], minimum_deposit_eth, transaction['data']).transact()
|
||||
tx = reentrancy_contract.functions.setData(1, transaction['to'], deposit_eth, transaction['data']).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = testerchain.client.send_transaction({'to': contract_address})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.workInfo(contract_address).call()[0] == minimum_deposit_eth
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == minimum_deposit_eth
|
||||
assert worklock.functions.workInfo(contract_address).call()[0] == deposit_eth
|
||||
assert testerchain.w3.eth.getBalance(worklock.address) == deposit_eth
|
||||
tx = worklock.functions.bid().transact({'from': testerchain.etherbase_account, 'value': deposit_eth})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Check reentrancy protection when cancelling a bid
|
||||
balance = testerchain.w3.eth.getBalance(contract_address)
|
||||
transaction = worklock.functions.cancelBid().buildTransaction({'gas': 0})
|
||||
tx = reentrancy_contract.functions.setData(2, transaction['to'], 0, transaction['data']).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = testerchain.client.send_transaction({'to': contract_address})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert testerchain.w3.eth.getBalance(contract_address) == balance
|
||||
assert worklock.functions.workInfo(contract_address).call()[0] == deposit_eth
|
||||
assert len(canceling_log.get_all_entries()) == 0
|
||||
|
||||
# Claim
|
||||
testerchain.time_travel(seconds=3600) # Wait exactly 1 hour
|
||||
|
@ -346,20 +522,21 @@ def test_reentrancy(testerchain, token_economics, deploy_contract, token, escrow
|
|||
testerchain.wait_for_receipt(tx)
|
||||
tx = testerchain.client.send_transaction({'to': contract_address})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.getRemainingWork(contract_address).call() == minimum_deposit_eth * refund_rate
|
||||
preallocation_escrow = worklock.functions.workInfo(contract_address).call()[2]
|
||||
assert worklock.functions.getRemainingWork(preallocation_escrow).call() == worklock_supply // 2
|
||||
|
||||
# Prepare for refund and check reentrancy protection
|
||||
balance = testerchain.w3.eth.getBalance(contract_address)
|
||||
completed_work = refund_rate * minimum_deposit_eth // 3
|
||||
tx = escrow.functions.setCompletedWork(contract_address, completed_work).transact()
|
||||
completed_work = worklock_supply // 6
|
||||
tx = escrow.functions.setCompletedWork(preallocation_escrow, completed_work).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
transaction = worklock.functions.refund().buildTransaction({'gas': 0})
|
||||
transaction = worklock.functions.refund(preallocation_escrow).buildTransaction({'gas': 0})
|
||||
tx = reentrancy_contract.functions.setData(2, transaction['to'], 0, transaction['data']).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = testerchain.client.send_transaction({'to': contract_address})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert testerchain.w3.eth.getBalance(contract_address) == balance
|
||||
assert worklock.functions.workInfo(contract_address).call()[0] == minimum_deposit_eth
|
||||
assert worklock.functions.getRemainingWork(contract_address).call() == 2 * minimum_deposit_eth * refund_rate // 3
|
||||
assert worklock.functions.workInfo(contract_address).call()[0] == deposit_eth
|
||||
assert worklock.functions.getRemainingWork(preallocation_escrow).call() == 2 * worklock_supply // 6
|
||||
assert len(refund_log.get_all_entries()) == 0
|
||||
|
|
|
@ -19,14 +19,14 @@ import os
|
|||
import pytest
|
||||
import requests
|
||||
from eth_utils import keccak
|
||||
from web3.exceptions import ValidationError
|
||||
|
||||
from nucypher.blockchain.eth.deployers import NucypherTokenDeployer, StakingEscrowDeployer, PolicyManagerDeployer, \
|
||||
AdjudicatorDeployer, BaseContractDeployer, UpgradeableContractMixin, DispatcherDeployer
|
||||
AdjudicatorDeployer, BaseContractDeployer
|
||||
from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory, BlockchainDeployerInterface
|
||||
from nucypher.blockchain.eth.registry import InMemoryContractRegistry, BaseContractRegistry
|
||||
from nucypher.blockchain.eth.registry import InMemoryContractRegistry
|
||||
from nucypher.blockchain.eth.sol.compile import SolidityCompiler, SourceDirs
|
||||
from nucypher.crypto.powers import TransactingPower
|
||||
from nucypher.utilities.sandbox.blockchain import TesterBlockchain
|
||||
from nucypher.utilities.sandbox.constants import INSECURE_DEVELOPMENT_PASSWORD, STAKING_ESCROW_DEPLOYMENT_SECRET, \
|
||||
POLICY_MANAGER_DEPLOYMENT_SECRET, ADJUDICATOR_DEPLOYMENT_SECRET
|
||||
|
||||
|
@ -65,10 +65,10 @@ def download_github_file(source_link: str, target_folder: str):
|
|||
|
||||
|
||||
# Constructor parameters overrides for previous versions if needed
|
||||
# All versions below the specified version must use these overrides
|
||||
# 'None' value removes arg from list of constructor parameters
|
||||
CONSTRUCTOR_OVERRIDES = {
|
||||
# Test example
|
||||
StakingEscrowDeployer.contract_name: {"v0.0.0": {"_hoursPerPeriod": 1}}
|
||||
StakingEscrowDeployer.contract_name: {"v1.5.1": {"_isTestContract": None}}
|
||||
}
|
||||
|
||||
|
||||
|
@ -76,13 +76,15 @@ def deploy_earliest_contract(blockchain_interface: BlockchainDeployerInterface,
|
|||
deployer: BaseContractDeployer,
|
||||
secret: str):
|
||||
contract_name = deployer.contract_name
|
||||
earliest_version, _data = blockchain_interface.find_raw_contract_data(contract_name, "earliest")
|
||||
latest_version, _data = blockchain_interface.find_raw_contract_data(contract_name, "latest")
|
||||
try:
|
||||
overrides = CONSTRUCTOR_OVERRIDES[contract_name][earliest_version]
|
||||
overrides = CONSTRUCTOR_OVERRIDES[contract_name][latest_version]
|
||||
except KeyError:
|
||||
overrides = dict()
|
||||
|
||||
deployer.deploy(secret_hash=keccak(text=secret), contract_version=earliest_version, **overrides)
|
||||
try:
|
||||
deployer.deploy(secret_hash=keccak(text=secret), contract_version="earliest", **overrides)
|
||||
except ValidationError:
|
||||
pass # Skip errors related to initialization
|
||||
|
||||
|
||||
def upgrade_to_latest_contract(deployer, secret: str):
|
||||
|
@ -128,10 +130,8 @@ def test_upgradeability(temp_dir_path, token_economics):
|
|||
|
||||
staking_escrow_deployer = StakingEscrowDeployer(registry=registry, deployer_address=origin)
|
||||
deploy_earliest_contract(blockchain_interface, staking_escrow_deployer, secret=STAKING_ESCROW_DEPLOYMENT_SECRET)
|
||||
assert staking_escrow_deployer.contract.functions.secondsPerPeriod().call() == 3600
|
||||
if test_staking_escrow:
|
||||
upgrade_to_latest_contract(staking_escrow_deployer, secret=STAKING_ESCROW_DEPLOYMENT_SECRET)
|
||||
assert staking_escrow_deployer.contract.functions.secondsPerPeriod().call() == token_economics.seconds_per_period
|
||||
|
||||
if test_policy_manager:
|
||||
policy_manager_deployer = PolicyManagerDeployer(registry=registry, deployer_address=origin)
|
||||
|
|
|
@ -55,7 +55,8 @@ def test_nucypher_deploy_contracts(click_runner,
|
|||
command = ['contracts',
|
||||
'--registry-outfile', registry_filepath,
|
||||
'--provider', TEST_PROVIDER_URI,
|
||||
'--poa']
|
||||
'--poa',
|
||||
'--se-test-mode']
|
||||
|
||||
user_input = '0\n' + 'Y\n' + (f'{INSECURE_SECRETS[1]}\n' * 8) + 'DEPLOY'
|
||||
result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False)
|
||||
|
@ -101,6 +102,7 @@ def test_nucypher_deploy_contracts(click_runner,
|
|||
assert token_agent.get_balance() == 0
|
||||
staking_agent = ContractAgency.get_agent(StakingEscrowAgent, registry=registry)
|
||||
assert staking_agent.get_current_period()
|
||||
assert staking_agent.contract.functions.isTestContract().call()
|
||||
|
||||
# and at least the others can be instantiated
|
||||
assert PolicyManagerAgent(registry=registry)
|
||||
|
|
|
@ -457,7 +457,7 @@ def _make_agency(testerchain, test_registry):
|
|||
token_deployer = NucypherTokenDeployer(deployer_address=origin, registry=test_registry)
|
||||
token_deployer.deploy()
|
||||
|
||||
staking_escrow_deployer = StakingEscrowDeployer(deployer_address=origin, registry=test_registry)
|
||||
staking_escrow_deployer = StakingEscrowDeployer(deployer_address=origin, registry=test_registry, test_mode=True)
|
||||
staking_escrow_deployer.deploy(secret_hash=INSECURE_DEPLOYMENT_SECRET_HASH)
|
||||
|
||||
policy_manager_deployer = PolicyManagerDeployer(deployer_address=origin, registry=test_registry)
|
||||
|
|
Loading…
Reference in New Issue