diff --git a/nkms_eth/project/contracts/Escrow.sol b/nkms_eth/project/contracts/Escrow.sol index a82a10c73..de79de1b9 100644 --- a/nkms_eth/project/contracts/Escrow.sol +++ b/nkms_eth/project/contracts/Escrow.sol @@ -224,6 +224,42 @@ contract Escrow is Miner, Ownable { return _lockedTokens.divCeil(info.releaseRate).sub(1); } + /** + * @notice Pre-deposit tokens + * @param _owners Tokens owners + * @param _values Amount of token to deposit for owners + * @param _periods Amount of periods during which tokens will be unlocked + **/ + function preDeposit(address[] _owners, uint256[] _values, uint256 _periods) + public isInitialized onlyOwner + { + require(_owners.length != 0 && + tokenOwners.sizeOf().add(_owners.length) <= MAX_OWNERS && + _owners.length == _values.length && + _periods >= minReleasePeriods); + var currentPeriod = getCurrentPeriod(); + uint256 allValue = 0; + + for (uint256 i = 0; i < _owners.length; i++) { + var owner = _owners[i]; + var value = _values[i]; + require(!tokenOwners.valueExists(owner) && + value >= minAllowableLockedTokens); + // TODO optimize + tokenOwners.push(owner, true); + var info = tokenInfo[owner]; + info.lastActivePeriod = currentPeriod; + info.value = value; + info.lockedValue = value; + info.maxReleasePeriods = _periods; + info.releaseRate = Math.max256(value.divCeil(_periods), 1); + info.release = false; + allValue = allValue.add(value); + } + + token.safeTransferFrom(msg.sender, address(this), allValue); + } + /** * @notice Deposit tokens * @param _value Amount of token to deposit diff --git a/scripts/estimate_gas_tester.py b/scripts/estimate_gas_tester.py index 105daecc6..beeec5fad 100644 --- a/scripts/estimate_gas_tester.py +++ b/scripts/estimate_gas_tester.py @@ -35,7 +35,7 @@ def main(): # Creator deploys the escrow escrow, _ = chain.provider.get_or_deploy_contract( - 'Escrow', deploy_args=[token.address, 1, 4 * 2 * 10 ** 7, 4, 4, 1], + 'Escrow', deploy_args=[token.address, 1, 4 * 2 * 10 ** 7, 4, 4, 1, 0], deploy_transaction={'from': creator}) # Creator deploys the policy manager @@ -52,8 +52,14 @@ def main(): chain.wait.for_receipt(tx) print("Estimate gas:") + # Pre deposit tokens + tx = token.transact({'from': creator}).approve(escrow.address, 10000) + chain.wait.for_receipt(tx) + print("Pre-deposit tokens fro 5 owners = " + + str(escrow.estimateGas({'from': creator}).preDeposit( + web3.eth.accounts[4:9], [1000] * 5, 1))) - # Give Ursula and Alice some coins + # Give some coins print("Transfer tokens = " + str(token.estimateGas({'from': creator}).transfer(ursula1, 10000))) tx = token.transact({'from': creator}).transfer(ursula1, 10000) @@ -63,7 +69,7 @@ def main(): tx = token.transact({'from': creator}).transfer(ursula3, 10000) chain.wait.for_receipt(tx) - # Ursula and Alice give Escrow rights to transfer + # Give Escrow rights to transfer print("Approving transfer = " + str(token.estimateGas({'from': ursula1}).approve(escrow.address, 1001))) tx = token.transact({'from': ursula1}).approve(escrow.address, 1001) @@ -73,7 +79,7 @@ def main(): tx = token.transact({'from': ursula3}).approve(escrow.address, 501) chain.wait.for_receipt(tx) - # Ursula and Alice transfer some tokens to the escrow and lock them + # Transfer some tokens to the escrow and lock them print("First deposit tokens = " + str(escrow.estimateGas({'from': ursula1}).deposit(1000, 1))) tx = escrow.transact({'from': ursula1}).deposit(1000, 1) diff --git a/tests/contracts/test_escrow.py b/tests/contracts/test_escrow.py index 7ff6844e1..35abd06d9 100644 --- a/tests/contracts/test_escrow.py +++ b/tests/contracts/test_escrow.py @@ -67,11 +67,6 @@ def test_escrow(web3, chain, token, escrow): assert 0 == escrow.call().getLockedTokens(alice) assert 0 == escrow.call().getLockedTokens(web3.eth.accounts[3]) - # Ursula can't deposit and lock too low value - with pytest.raises(TransactionFailed): - tx = escrow.transact({'from': ursula}).deposit(1, 1) - chain.wait.for_receipt(tx) - # Ursula can't deposit tokens before Escrow initialization with pytest.raises(TransactionFailed): tx = escrow.transact({'from': ursula}).deposit(1, 1) @@ -81,6 +76,11 @@ def test_escrow(web3, chain, token, escrow): tx = escrow.transact().initialize() chain.wait.for_receipt(tx) + # Ursula can't deposit and lock too low value + with pytest.raises(TransactionFailed): + tx = escrow.transact({'from': ursula}).deposit(1, 1) + chain.wait.for_receipt(tx) + # Ursula and Alice transfer some tokens to the escrow and lock them tx = escrow.transact({'from': ursula}).deposit(1000, 1) chain.wait.for_receipt(tx) @@ -467,3 +467,40 @@ def test_mining(web3, chain, token, escrow): assert 10134 == token.call().balanceOf(alice) # TODO test max confirmed periods and miners + + +def test_pre_deposit(web3, chain, token, escrow): + creator = web3.eth.accounts[0] + + # Initialize Escrow contract + tx = escrow.transact().initialize() + chain.wait.for_receipt(tx) + + # Grant access to transfer tokens + tx = token.transact({'from': creator}).approve(escrow.address, 10000) + chain.wait.for_receipt(tx) + + # Deposit tokens for 1 owner + owner = web3.eth.accounts[1] + tx = escrow.transact({'from': creator}).preDeposit([owner], [1000], 10) + chain.wait.for_receipt(tx) + assert 1000 == token.call().balanceOf(escrow.address) + assert 1000 == escrow.call().getTokens(owner) + assert 1000 == escrow.call().getLockedTokens(owner) + assert 10 == escrow.call().tokenInfo(owner)[4] + + # Can't pre-deposit tokens again for same owner + with pytest.raises(TransactionFailed): + tx = escrow.transact({'from': creator}).preDeposit( + [web3.eth.accounts[1]], [1000], 10) + chain.wait.for_receipt(tx) + + # Deposit tokens for multiple owners + owners = web3.eth.accounts[2:7] + tx = escrow.transact({'from': creator}).preDeposit(owners, [100] * 5, 100) + chain.wait.for_receipt(tx) + assert 1500 == token.call().balanceOf(escrow.address) + for owner in owners: + assert 100 == escrow.call().getTokens(owner) + assert 100 == escrow.call().getLockedTokens(owner) + assert 100 == escrow.call().tokenInfo(owner)[4]