mirror of https://github.com/nucypher/nucypher.git
Fixed the approveAndCall method in the token contract, added implementation of the receiveApproval method in the escrow contract
parent
33ff3d0955
commit
01a1a6d7d7
|
@ -201,22 +201,62 @@ contract MinersEscrow is Issuer {
|
|||
token.safeTransferFrom(msg.sender, address(this), allValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Implementation of the receiveApproval(address,uint256,address,bytes) method
|
||||
* (see NuCypherToken contract). Deposit all tokens that were approved to transfer
|
||||
* @param _from Tokens owner
|
||||
* @param _value Amount of token to deposit
|
||||
* @param _tokenContract Token contract address
|
||||
* @param _extraData Extra data - amount of periods during which tokens will be locked
|
||||
**/
|
||||
function receiveApproval(
|
||||
address _from,
|
||||
uint256 _value,
|
||||
address _tokenContract,
|
||||
bytes _extraData
|
||||
)
|
||||
external
|
||||
{
|
||||
require(_tokenContract == address(token) && msg.sender == address(token));
|
||||
// copy first 32 bytes from _extraData. Position is calculated as
|
||||
// 4 bytes method signature plus 32 * 3 bytes for previous params and
|
||||
// addition 32 bytes to skip _extraData pointer
|
||||
uint256 payloadSize;
|
||||
uint256 payload;
|
||||
assembly {
|
||||
payloadSize := calldataload(0x84)
|
||||
payload := calldataload(0xA4)
|
||||
}
|
||||
payload = payload >> 8*(32 - payloadSize);
|
||||
deposit(_from, _value, payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Deposit tokens
|
||||
* @param _value Amount of token to deposit
|
||||
* @param _periods Amount of periods during which tokens will be locked
|
||||
**/
|
||||
function deposit(uint256 _value, uint256 _periods) public isInitialized {
|
||||
function deposit(uint256 _value, uint256 _periods) public {
|
||||
deposit(msg.sender, _value, _periods);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Deposit tokens
|
||||
* @param _owner Tokens owner
|
||||
* @param _value Amount of token to deposit
|
||||
* @param _periods Amount of periods during which tokens will be locked
|
||||
**/
|
||||
function deposit(address _owner, uint256 _value, uint256 _periods) internal isInitialized {
|
||||
require(_value != 0);
|
||||
MinerInfo storage info = minerInfo[msg.sender];
|
||||
if (minerInfo[msg.sender].value == 0) {
|
||||
miners.push(msg.sender);
|
||||
MinerInfo storage info = minerInfo[_owner];
|
||||
if (info.lastActivePeriod == 0) {
|
||||
miners.push(_owner);
|
||||
info.lastActivePeriod = getCurrentPeriod();
|
||||
}
|
||||
info.value = info.value.add(_value);
|
||||
token.safeTransferFrom(msg.sender, address(this), _value);
|
||||
lock(_value, _periods);
|
||||
emit Deposited(msg.sender, _value, _periods);
|
||||
token.safeTransferFrom(_owner, address(this), _value);
|
||||
lock(_owner, _value, _periods);
|
||||
emit Deposited(_owner, _value, _periods);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -225,11 +265,21 @@ contract MinersEscrow is Issuer {
|
|||
* @param _periods Amount of periods during which tokens will be locked
|
||||
**/
|
||||
function lock(uint256 _value, uint256 _periods) public onlyTokenOwner {
|
||||
require(_value != 0 || _periods != 0);
|
||||
mint();
|
||||
lock(msg.sender, _value, _periods);
|
||||
}
|
||||
|
||||
uint256 lockedTokens = getLockedTokens(msg.sender, 1);
|
||||
MinerInfo storage info = minerInfo[msg.sender];
|
||||
/**
|
||||
* @notice Lock some tokens or increase lock
|
||||
* @param _owner Tokens owner
|
||||
* @param _value Amount of tokens which should lock
|
||||
* @param _periods Amount of periods during which tokens will be locked
|
||||
**/
|
||||
function lock(address _owner, uint256 _value, uint256 _periods) internal {
|
||||
require(_value != 0 || _periods != 0);
|
||||
mint(_owner);
|
||||
|
||||
uint256 lockedTokens = getLockedTokens(_owner, 1);
|
||||
MinerInfo storage info = minerInfo[_owner];
|
||||
require(_value <= token.balanceOf(address(this)) &&
|
||||
_value <= info.value.sub(lockedTokens) &&
|
||||
_value >= minAllowableLockedTokens &&
|
||||
|
@ -239,8 +289,8 @@ contract MinersEscrow is Issuer {
|
|||
uint256 currentPeriod = getCurrentPeriod();
|
||||
info.stakes.push(StakeInfo(currentPeriod.add(uint256(1)), currentPeriod.add(_periods), _value));
|
||||
|
||||
confirmActivity(_value + lockedTokens, _value);
|
||||
emit Locked(msg.sender, _value, currentPeriod + 1, currentPeriod + _periods);
|
||||
confirmActivity(_owner, _value + lockedTokens, _value);
|
||||
emit Locked(_owner, _value, currentPeriod + 1, currentPeriod + _periods);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -294,23 +344,24 @@ contract MinersEscrow is Issuer {
|
|||
|
||||
/**
|
||||
* @notice Confirm activity for future period
|
||||
* @param _owner Tokens owner
|
||||
* @param _lockedValue Locked tokens in future period
|
||||
* @param _additional Additional locked tokens in future period.
|
||||
* Used only if the period has already been confirmed
|
||||
**/
|
||||
function confirmActivity(uint256 _lockedValue, uint256 _additional) internal {
|
||||
function confirmActivity(address _owner, uint256 _lockedValue, uint256 _additional) internal {
|
||||
require(_lockedValue > 0);
|
||||
MinerInfo storage info = minerInfo[msg.sender];
|
||||
MinerInfo storage info = minerInfo[_owner];
|
||||
uint256 nextPeriod = getCurrentPeriod() + 1;
|
||||
|
||||
// update lockedValue if the period has already been confirmed
|
||||
if (info.confirmedPeriod1 == nextPeriod) {
|
||||
lockedPerPeriod[nextPeriod] = lockedPerPeriod[nextPeriod].add(_additional);
|
||||
emit ActivityConfirmed(msg.sender, nextPeriod, _additional);
|
||||
emit ActivityConfirmed(_owner, nextPeriod, _additional);
|
||||
return;
|
||||
} else if (info.confirmedPeriod2 == nextPeriod) {
|
||||
lockedPerPeriod[nextPeriod] = lockedPerPeriod[nextPeriod].add(_additional);
|
||||
emit ActivityConfirmed(msg.sender, nextPeriod, _additional);
|
||||
emit ActivityConfirmed(_owner, nextPeriod, _additional);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -326,14 +377,14 @@ contract MinersEscrow is Issuer {
|
|||
info.downtime.push(Downtime(info.lastActivePeriod + 1, currentPeriod));
|
||||
}
|
||||
info.lastActivePeriod = nextPeriod;
|
||||
emit ActivityConfirmed(msg.sender, nextPeriod, _lockedValue);
|
||||
emit ActivityConfirmed(_owner, nextPeriod, _lockedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Confirm activity for future period and mine for previous period
|
||||
**/
|
||||
function confirmActivity() external onlyTokenOwner {
|
||||
mint();
|
||||
mint(msg.sender);
|
||||
MinerInfo storage info = minerInfo[msg.sender];
|
||||
uint256 currentPeriod = getCurrentPeriod();
|
||||
uint256 nextPeriod = currentPeriod + 1;
|
||||
|
@ -345,15 +396,23 @@ contract MinersEscrow is Issuer {
|
|||
}
|
||||
|
||||
uint256 lockedTokens = getLockedTokens(msg.sender, 1);
|
||||
confirmActivity(lockedTokens, 0);
|
||||
confirmActivity(msg.sender, lockedTokens, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Mint tokens for sender for previous periods if he locked his tokens and confirmed activity
|
||||
**/
|
||||
function mint() public onlyTokenOwner {
|
||||
mint(msg.sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Mint tokens for owner for previous periods if he locked his tokens and confirmed activity
|
||||
* @param _owner Tokens owner
|
||||
**/
|
||||
function mint(address _owner) internal {
|
||||
uint256 previousPeriod = getCurrentPeriod().sub(uint(1));
|
||||
MinerInfo storage info = minerInfo[msg.sender];
|
||||
MinerInfo storage info = minerInfo[_owner];
|
||||
|
||||
if (info.confirmedPeriod1 > previousPeriod &&
|
||||
info.confirmedPeriod2 > previousPeriod ||
|
||||
|
@ -379,51 +438,53 @@ contract MinersEscrow is Issuer {
|
|||
uint256 reward = 0;
|
||||
if (info.confirmedPeriod1 != EMPTY_CONFIRMED_PERIOD &&
|
||||
info.confirmedPeriod1 < info.confirmedPeriod2) {
|
||||
reward = reward.add(mint(info, info.confirmedPeriod1, previousPeriod));
|
||||
reward = reward.add(mint(_owner, info, info.confirmedPeriod1, previousPeriod));
|
||||
info.confirmedPeriod1 = EMPTY_CONFIRMED_PERIOD;
|
||||
} else if (info.confirmedPeriod2 != EMPTY_CONFIRMED_PERIOD &&
|
||||
info.confirmedPeriod2 < info.confirmedPeriod1) {
|
||||
reward = reward.add(mint(info, info.confirmedPeriod2, previousPeriod));
|
||||
reward = reward.add(mint(_owner, info, info.confirmedPeriod2, previousPeriod));
|
||||
info.confirmedPeriod2 = EMPTY_CONFIRMED_PERIOD;
|
||||
}
|
||||
if (info.confirmedPeriod2 <= previousPeriod &&
|
||||
info.confirmedPeriod2 > info.confirmedPeriod1) {
|
||||
reward = reward.add(mint(info, info.confirmedPeriod2, previousPeriod));
|
||||
reward = reward.add(mint(_owner, info, info.confirmedPeriod2, previousPeriod));
|
||||
info.confirmedPeriod2 = EMPTY_CONFIRMED_PERIOD;
|
||||
} else if (info.confirmedPeriod1 <= previousPeriod &&
|
||||
info.confirmedPeriod1 > info.confirmedPeriod2) {
|
||||
reward = reward.add(mint(info, info.confirmedPeriod1, previousPeriod));
|
||||
reward = reward.add(mint(_owner, info, info.confirmedPeriod1, previousPeriod));
|
||||
info.confirmedPeriod1 = EMPTY_CONFIRMED_PERIOD;
|
||||
}
|
||||
|
||||
info.value = info.value.add(reward);
|
||||
emit Mined(msg.sender, previousPeriod, reward);
|
||||
emit Mined(_owner, previousPeriod, reward);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Calculate reward for one period
|
||||
**/
|
||||
function mint(MinerInfo storage info, uint256 period, uint256 previousPeriod)
|
||||
function mint(
|
||||
address _owner,
|
||||
MinerInfo storage _info,
|
||||
uint256 _period,
|
||||
uint256 _previousPeriod
|
||||
)
|
||||
internal returns (uint256 reward)
|
||||
{
|
||||
uint256 amount;
|
||||
for (uint256 i = 0; i < info.stakes.length; i++) {
|
||||
StakeInfo storage stake = info.stakes[i];
|
||||
if (stake.firstPeriod <= period &&
|
||||
stake.lastPeriod >= period) {
|
||||
(amount, info.decimals) = mint(
|
||||
previousPeriod,
|
||||
for (uint256 i = 0; i < _info.stakes.length; i++) {
|
||||
StakeInfo storage stake = _info.stakes[i];
|
||||
if (stake.firstPeriod <= _period &&
|
||||
stake.lastPeriod >= _period) {
|
||||
(amount, _info.decimals) = mint(
|
||||
_previousPeriod,
|
||||
stake.lockedValue,
|
||||
lockedPerPeriod[period],
|
||||
stake.lastPeriod.sub(period),
|
||||
info.decimals);
|
||||
lockedPerPeriod[_period],
|
||||
stake.lastPeriod.sub(_period),
|
||||
_info.decimals);
|
||||
reward = reward.add(amount);
|
||||
}
|
||||
}
|
||||
// TODO remove if
|
||||
if (address(policyManager) != 0x0) {
|
||||
policyManager.updateReward(msg.sender, period);
|
||||
}
|
||||
policyManager.updateReward(_owner, _period);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,18 +27,31 @@ contract NuCypherToken is StandardToken, DetailedERC20('NuCypher', 'NU', 18), Bu
|
|||
* @notice Approves and then calls the receiving contract
|
||||
*
|
||||
* @dev call the receiveApproval function on the contract you want to be notified.
|
||||
* This crafts the function signature manually so one doesn't have to include a contract in here just for this.
|
||||
* receiveApproval(address _from, uint256 _value, address _tokenContract, bytes _extraData)
|
||||
* it is assumed that when does this that the call *should* succeed, otherwise one would use vanilla approve instead.
|
||||
**/
|
||||
function approveAndCall(address _spender, uint256 _value, bytes _extraData)
|
||||
public returns (bool success)
|
||||
{
|
||||
approve(_spender, _value);
|
||||
|
||||
require(_spender.call(bytes4(keccak256("receiveApproval(address,uint256,address,bytes)")),
|
||||
msg.sender, _value, this, _extraData));
|
||||
TokenRecipient(_spender).receiveApproval(msg.sender, _value, address(this), _extraData);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dev Interface to use the receiveApproval method
|
||||
**/
|
||||
contract TokenRecipient {
|
||||
|
||||
/**
|
||||
* @notice Receives a notification of approval of the transfer
|
||||
* @param _from Sender of approval
|
||||
* @param _value The amount of tokens to be spent
|
||||
* @param _tokenContract Address of the token contract
|
||||
* @param _extraData Extra data
|
||||
**/
|
||||
function receiveApproval(address _from, uint256 _value, address _tokenContract, bytes _extraData) external;
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
pragma solidity ^0.4.23;
|
||||
|
||||
|
||||
/**
|
||||
* @notice Contract for using in token tests
|
||||
**/
|
||||
contract ReceiveApprovalMethodMock {
|
||||
|
||||
address public sender;
|
||||
uint256 public value;
|
||||
address public tokenContract;
|
||||
bytes public extraData;
|
||||
|
||||
function receiveApproval(
|
||||
address _from,
|
||||
uint256 _value,
|
||||
address _tokenContract,
|
||||
bytes _extraData
|
||||
)
|
||||
external
|
||||
{
|
||||
sender = _from;
|
||||
value = _value;
|
||||
tokenContract = _tokenContract;
|
||||
extraData = _extraData;
|
||||
}
|
||||
|
||||
}
|
|
@ -48,6 +48,12 @@ def test_escrow(web3, chain, token, escrow_contract):
|
|||
divides_log = escrow.events.Divided.createFilter(fromBlock='latest')
|
||||
withdraw_log = escrow.events.Withdrawn.createFilter(fromBlock='latest')
|
||||
|
||||
policy_manager, _ = chain.provider.deploy_contract(
|
||||
'PolicyManagerForMinersEscrowMock', token.address, escrow.address
|
||||
)
|
||||
tx = escrow.functions.setPolicyManager(policy_manager.address).transact()
|
||||
chain.wait_for_receipt(tx)
|
||||
|
||||
# Give Ursula and Ursula(2) some coins
|
||||
tx = token.functions.transfer(ursula1, 10000).transact({'from': creator})
|
||||
chain.wait_for_receipt(tx)
|
||||
|
@ -57,12 +63,12 @@ def test_escrow(web3, chain, token, escrow_contract):
|
|||
assert 10000 == token.functions.balanceOf(ursula2).call()
|
||||
|
||||
# Ursula and Ursula(2) give Escrow rights to transfer
|
||||
tx = token.functions.approve(escrow.address, 3000).transact({'from': ursula1})
|
||||
tx = token.functions.approve(escrow.address, 1100).transact({'from': ursula1})
|
||||
chain.wait_for_receipt(tx)
|
||||
assert 3000 == token.functions.allowance(ursula1, escrow.address).call()
|
||||
tx = token.functions.approve(escrow.address, 1100).transact({'from': ursula2})
|
||||
assert 1100 == token.functions.allowance(ursula1, escrow.address).call()
|
||||
tx = token.functions.approve(escrow.address, 500).transact({'from': ursula2})
|
||||
chain.wait_for_receipt(tx)
|
||||
assert 1100 == token.functions.allowance(ursula2, escrow.address).call()
|
||||
assert 500 == token.functions.allowance(ursula2, escrow.address).call()
|
||||
|
||||
# Ursula's withdrawal attempt won't succeed because nothing to withdraw
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
|
@ -90,16 +96,25 @@ def test_escrow(web3, chain, token, escrow_contract):
|
|||
|
||||
# Ursula can't deposit and lock too low value
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = escrow.functions.deposit(1, 1).transact({'from': ursula1})
|
||||
tx = escrow.functions.deposit(1, 10).transact({'from': ursula1})
|
||||
chain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = token.functions.approveAndCall(escrow.address, 1, web3.toBytes(10)).transact({'from': ursula1})
|
||||
chain.wait_for_receipt(tx)
|
||||
# And can't deposit and lock too high value
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = escrow.functions.deposit(1501, 1).transact({'from': ursula1})
|
||||
tx = escrow.functions.deposit(1501, 10).transact({'from': ursula1})
|
||||
chain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = token.functions.approveAndCall(escrow.address, 1501, web3.toBytes(10)).transact({'from': ursula1})
|
||||
chain.wait_for_receipt(tx)
|
||||
# And can't deposit for too short a period
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = escrow.functions.deposit(1000, 1).transact({'from': ursula1})
|
||||
chain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = token.functions.approveAndCall(escrow.address, 1000, web3.toBytes(1)).transact({'from': ursula1})
|
||||
chain.wait_for_receipt(tx)
|
||||
|
||||
# Ursula and Ursula(2) transfer some tokens to the escrow and lock them
|
||||
tx = escrow.functions.deposit(1000, 2).transact({'from': ursula1})
|
||||
|
@ -181,7 +196,7 @@ def test_escrow(web3, chain, token, escrow_contract):
|
|||
assert escrow.functions.getCurrentPeriod().call() + 1 == event_args['period']
|
||||
assert 1000 == event_args['value']
|
||||
|
||||
tx = escrow.functions.deposit(500, 2).transact({'from': ursula1})
|
||||
tx = token.functions.approveAndCall(escrow.address, 500, web3.toBytes(2)).transact({'from': ursula1})
|
||||
chain.wait_for_receipt(tx)
|
||||
assert 2000 == token.functions.balanceOf(escrow.address).call()
|
||||
assert 8500 == token.functions.balanceOf(ursula1).call()
|
||||
|
@ -194,7 +209,10 @@ def test_escrow(web3, chain, token, escrow_contract):
|
|||
|
||||
# But can't deposit too high value
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = escrow.functions.deposit(1, 2).transact({'from': ursula1})
|
||||
tx = escrow.functions.deposit(100, 2).transact({'from': ursula1})
|
||||
chain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = token.functions.approveAndCall(escrow.address, 100, web3.toBytes(2)).transact({'from': ursula1})
|
||||
chain.wait_for_receipt(tx)
|
||||
|
||||
# Wait 1 period and checks locking
|
||||
|
@ -216,7 +234,7 @@ def test_escrow(web3, chain, token, escrow_contract):
|
|||
assert 500 == event_args['value']
|
||||
|
||||
# And Ursula can withdraw some tokens
|
||||
tx = escrow.functions.withdraw(100).transact({'from': ursula1})
|
||||
tx = escrow.functions.withdraw(100).transact({'from': ursula1})
|
||||
chain.wait_for_receipt(tx)
|
||||
assert 1900 == token.functions.balanceOf(escrow.address).call()
|
||||
assert 8600 == token.functions.balanceOf(ursula1).call()
|
||||
|
@ -228,16 +246,16 @@ def test_escrow(web3, chain, token, escrow_contract):
|
|||
|
||||
# But Ursula can't withdraw all without mining for locked value
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = escrow.functions.withdraw(1400).transact({'from': ursula1})
|
||||
tx = escrow.functions.withdraw(1400).transact({'from': ursula1})
|
||||
chain.wait_for_receipt(tx)
|
||||
|
||||
# And Ursula can't lock again too low value
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = escrow.functions.lock(1, 1).transact({'from': ursula1})
|
||||
tx = escrow.functions.lock(1, 1).transact({'from': ursula1})
|
||||
chain.wait_for_receipt(tx)
|
||||
|
||||
# Ursula can deposit and lock more tokens
|
||||
tx = escrow.functions.deposit(500, 2).transact({'from': ursula1})
|
||||
tx = token.functions.approveAndCall(escrow.address, 500, web3.toBytes(2)).transact({'from': ursula1})
|
||||
chain.wait_for_receipt(tx)
|
||||
|
||||
events = activity_log.get_all_entries()
|
||||
|
@ -278,8 +296,8 @@ def test_escrow(web3, chain, token, escrow_contract):
|
|||
chain.time_travel(hours=1)
|
||||
assert 1100 == escrow.functions.getLockedTokens(ursula1).call()
|
||||
|
||||
# Ursula(2) increases lock by deposit more tokens
|
||||
tx = escrow.functions.deposit(500, 2).transact({'from': ursula2})
|
||||
# Ursula(2) increases lock by deposit more tokens using approveAndCall
|
||||
tx = token.functions.approveAndCall(escrow.address, 500, web3.toBytes(2)).transact({'from': ursula2})
|
||||
chain.wait_for_receipt(tx)
|
||||
assert 500 == escrow.functions.getLockedTokens(ursula2).call()
|
||||
assert 1000 == escrow.functions.getLockedTokens(ursula2, 1).call()
|
||||
|
@ -607,12 +625,16 @@ def test_mining(web3, chain, token, escrow_contract):
|
|||
tx = escrow.functions.lock(500, 2).transact({'from': ursula2})
|
||||
chain.wait_for_receipt(tx)
|
||||
|
||||
# Ursula(2) mint only one period
|
||||
# Ursula(2) mint only one period (by using deposit function)
|
||||
chain.time_travel(hours=5)
|
||||
tx = escrow.functions.mint().transact({'from': ursula2})
|
||||
tx = token.functions.approveAndCall(escrow.address, 100, web3.toBytes(2)).transact({'from': ursula2})
|
||||
chain.wait_for_receipt(tx)
|
||||
assert 1152 == escrow.functions.minerInfo(ursula1).call()[VALUE_FIELD]
|
||||
assert 842 == escrow.functions.minerInfo(ursula2).call()[VALUE_FIELD]
|
||||
assert 942 == escrow.functions.minerInfo(ursula2).call()[VALUE_FIELD]
|
||||
|
||||
period = escrow.functions.getCurrentPeriod().call() - 4
|
||||
assert 2 == policy_manager.functions.getPeriodsLength(ursula2).call()
|
||||
assert period == policy_manager.functions.getPeriod(ursula2, 1).call()
|
||||
|
||||
events = mining_log.get_all_entries()
|
||||
assert 4 == len(events)
|
||||
|
@ -622,7 +644,8 @@ def test_mining(web3, chain, token, escrow_contract):
|
|||
assert escrow.functions.getCurrentPeriod().call() - 1 == event_args['period']
|
||||
|
||||
# Ursula(2) can withdraw all
|
||||
tx = escrow.functions.withdraw(842).transact({'from': ursula2})
|
||||
chain.time_travel(hours=3)
|
||||
tx = escrow.functions.withdraw(942).transact({'from': ursula2})
|
||||
chain.wait_for_receipt(tx)
|
||||
assert 10092 == token.functions.balanceOf(ursula2).call()
|
||||
|
||||
|
@ -630,12 +653,12 @@ def test_mining(web3, chain, token, escrow_contract):
|
|||
assert 1 == len(events)
|
||||
event_args = events[0]['args']
|
||||
assert ursula2 == event_args['owner']
|
||||
assert 842 == event_args['value']
|
||||
assert 942 == event_args['value']
|
||||
|
||||
assert 3 == len(deposit_log.get_all_entries())
|
||||
assert 5 == len(lock_log.get_all_entries())
|
||||
assert 4 == len(deposit_log.get_all_entries())
|
||||
assert 6 == len(lock_log.get_all_entries())
|
||||
assert 1 == len(divides_log.get_all_entries())
|
||||
assert 6 == len(activity_log.get_all_entries())
|
||||
assert 7 == len(activity_log.get_all_entries())
|
||||
|
||||
|
||||
@pytest.mark.slow
|
||||
|
|
|
@ -18,13 +18,13 @@ def test_create_token(web3, chain):
|
|||
assert txhash is not None
|
||||
|
||||
# Account balances
|
||||
assert token.functions.balanceOf(creator).call() == 10 ** 9
|
||||
assert token.functions.balanceOf(account1).call() == 0
|
||||
assert 10 ** 9 == token.functions.balanceOf(creator).call()
|
||||
assert 0 == token.functions.balanceOf(account1).call()
|
||||
|
||||
# Basic properties
|
||||
assert token.functions.name().call() == 'NuCypher'
|
||||
assert token.functions.decimals().call() == 18
|
||||
assert token.functions.symbol().call() == 'NU'
|
||||
assert 'NuCypher' == token.functions.name().call()
|
||||
assert 18 == token.functions.decimals().call()
|
||||
assert 'NU' == token.functions.symbol().call()
|
||||
|
||||
# Cannot send ethers to the contract
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
|
@ -32,22 +32,54 @@ def test_create_token(web3, chain):
|
|||
chain.wait_for_receipt(tx)
|
||||
|
||||
# Can transfer tokens
|
||||
tx = token.functions.transfer(account1, 10000).transact({'from': creator})
|
||||
tx = token.functions.transfer(account1, 10000).transact({'from': creator})
|
||||
chain.wait_for_receipt(tx)
|
||||
assert token.functions.balanceOf(account1).call() == 10000
|
||||
assert token.functions.balanceOf(creator).call() == 10 ** 9 - 10000
|
||||
assert 10000 == token.functions.balanceOf(account1).call()
|
||||
assert 10 ** 9 - 10000 == token.functions.balanceOf(creator).call()
|
||||
|
||||
tx = token.functions.transfer(account2, 10).transact({'from': account1})
|
||||
tx = token.functions.transfer(account2, 10).transact({'from': account1})
|
||||
chain.wait_for_receipt(tx)
|
||||
assert token.functions.balanceOf(account1).call() == 10000 - 10
|
||||
assert token.functions.balanceOf(account2).call() == 10
|
||||
assert 10000 - 10 == token.functions.balanceOf(account1).call()
|
||||
assert 10 == token.functions.balanceOf(account2).call()
|
||||
|
||||
tx = token.functions.transfer(token.address, 10).transact({'from': account1})
|
||||
tx = token.functions.transfer(token.address, 10).transact({'from': account1})
|
||||
chain.wait_for_receipt(tx)
|
||||
assert token.functions.balanceOf(token.address).call() == 10
|
||||
assert 10 == token.functions.balanceOf(token.address).call()
|
||||
|
||||
# Can burn own tokens
|
||||
tx = token.functions.burn(1).transact({'from': account2})
|
||||
tx = token.functions.burn(1).transact({'from': account2})
|
||||
chain.wait_for_receipt(tx)
|
||||
assert token.functions.balanceOf(account2).call() == 9
|
||||
assert token.functions.totalSupply().call() == 10 ** 9 - 1
|
||||
assert 9 == token.functions.balanceOf(account2).call()
|
||||
assert 10 ** 9 - 1 == token.functions.totalSupply().call()
|
||||
|
||||
|
||||
def test_approve_and_call(web3, chain):
|
||||
creator = web3.eth.accounts[0]
|
||||
account1 = web3.eth.accounts[1]
|
||||
account2 = web3.eth.accounts[2]
|
||||
|
||||
token, _ = chain.provider.deploy_contract('NuCypherToken', 10 ** 9)
|
||||
mock, _ = chain.provider.deploy_contract('ReceiveApprovalMethodMock')
|
||||
|
||||
tx = token.functions.approve(account1, 100).transact({'from': creator})
|
||||
chain.wait_for_receipt(tx)
|
||||
assert 100 == token.functions.allowance(creator, account1).call()
|
||||
assert 0 == token.functions.allowance(creator, account2).call()
|
||||
assert 0 == token.functions.allowance(account1, creator).call()
|
||||
assert 0 == token.functions.allowance(account1, account2).call()
|
||||
assert 0 == token.functions.allowance(account2, account1).call()
|
||||
|
||||
tx = token.functions.transferFrom(creator, account2, 50).transact({'from': account1})
|
||||
chain.wait_for_receipt(tx)
|
||||
assert 50 == token.functions.balanceOf(account2).call()
|
||||
assert 50 == token.functions.allowance(creator, account1).call()
|
||||
|
||||
tx = token.functions.approveAndCall(mock.address, 25, web3.toBytes(111)).transact({'from': account1})
|
||||
chain.wait_for_receipt(tx)
|
||||
assert 50 == token.functions.balanceOf(account2).call()
|
||||
assert 50 == token.functions.allowance(creator, account1).call()
|
||||
assert 25 == token.functions.allowance(account1, mock.address).call()
|
||||
assert account1 == mock.functions.sender().call()
|
||||
assert 25 == mock.functions.value().call()
|
||||
assert token.address == mock.functions.tokenContract().call()
|
||||
assert 111 == web3.toInt(mock.functions.extraData().call())
|
||||
|
|
Loading…
Reference in New Issue