def test_failed_send_in_withdraw(self): external_code = """ contract ERC20 { function deposit() payable; function withdraw(uint256 _value) returns (bool success); } contract Dummy { address private erc20_addr; uint256 val; function Dummy(address _erc20_addr) { erc20_addr = _erc20_addr; } function my_deposit() external payable { val = msg.value; ERC20(erc20_addr).deposit.value(val)(); } function my_withdraw() returns (bool success) { return ERC20(erc20_addr).withdraw(val); } function() external payable { throw; } } """ # deploy the contract and pass the ERC20 contract's address as argument ext = self.s.contract(external_code, args=[self.c.address], language='solidity') # deposit should work and a Deposit event should be logged self.assertIsNone(ext.my_deposit(value=2)) self.check_logs([self.transfer_topic, 0, bytes_to_int(ext.address)], (2).to_bytes(32, byteorder='big')) # withdraw should throw self.assert_tx_failed(lambda: ext.my_withdraw()) # re-deploy the contract with a working default function external_code2 = external_code.replace("throw", "return") ext2 = self.s.contract(external_code2, args=[self.c.address], language='solidity') # deposit should work and yield the correct event self.assertIsNone(ext2.my_deposit(value=2)) self.check_logs([self.transfer_topic, 0, bytes_to_int(ext2.address)], (2).to_bytes(32, byteorder='big')) # withdraw should work and yield the correct event self.assertTrue(ext2.my_withdraw()) self.check_logs([self.transfer_topic, bytes_to_int(ext2.address), 0], (2).to_bytes(32, byteorder='big'))
def test_logging(self): # test a callback to log an event self.hydra.HYDRA_INIT(self.external.address, self.hydra.address) kall(self.t, self.s, self.ct, self.hydra.address, "log_event") t = bytes_to_int(utils.sha3("LogCallBack1(uint256,uint256)")) self.check_logs([t], int_to_bytes(1) + int_to_bytes(2))
def test_raw_logs(self): self.s.head_state.receipts[-1].logs = [] # Check that deposit appropriately emits Deposit event self.assertIsNone(self.c.deposit(value=2, sender=self.t.k1)) self.check_logs([self.transfer_topic, 0, bytes_to_int(self.t.a1)], (2).to_bytes(32, byteorder='big')) self.assertIsNone(self.c.deposit(value=0, sender=self.t.k1)) self.check_logs([self.transfer_topic, 0, bytes_to_int(self.t.a1)], (0).to_bytes(32, byteorder='big')) # Check that withdraw appropriately emits Withdraw event self.assertTrue(self.c.withdraw(1, sender=self.t.k1)) self.check_logs([self.transfer_topic, bytes_to_int(self.t.a1), 0], (1).to_bytes(32, byteorder='big')) self.assertTrue(self.c.withdraw(0, sender=self.t.k1)) self.check_logs([self.transfer_topic, bytes_to_int(self.t.a1), 0], (0).to_bytes(32, byteorder='big')) # Check that transfer appropriately emits Transfer event self.assertTrue(self.c.transfer(self.t.a2, 1, sender=self.t.k1)) self.check_logs([ self.transfer_topic, bytes_to_int(self.t.a1), bytes_to_int(self.t.a2) ], (1).to_bytes(32, byteorder='big')) self.assertTrue(self.c.transfer(self.t.a2, 0, sender=self.t.k1)) self.check_logs([ self.transfer_topic, bytes_to_int(self.t.a1), bytes_to_int(self.t.a2) ], (0).to_bytes(32, byteorder='big')) # Check that approving amount emits events self.assertTrue(self.c.approve(self.t.a1, 1, sender=self.t.k2)) self.check_logs([ self.approval_topic, bytes_to_int(self.t.a2), bytes_to_int(self.t.a1) ], (1).to_bytes(32, byteorder='big')) self.assertTrue(self.c.approve(self.t.a2, 0, sender=self.t.k3)) self.check_logs([ self.approval_topic, bytes_to_int(self.t.a3), bytes_to_int(self.t.a2) ], (0).to_bytes(32, byteorder='big')) # Check that transferFrom appropriately emits Transfer event self.assertTrue( self.c.transferFrom(self.t.a2, self.t.a3, 1, sender=self.t.k1)) self.check_logs([ self.transfer_topic, bytes_to_int(self.t.a2), bytes_to_int(self.t.a3) ], (1).to_bytes(32, byteorder='big')) self.assertTrue( self.c.transferFrom(self.t.a2, self.t.a3, 0, sender=self.t.k1)) self.check_logs([ self.transfer_topic, bytes_to_int(self.t.a2), bytes_to_int(self.t.a3) ], (0).to_bytes(32, byteorder='big')) # Check that no other ERC-compliant calls emit any events self.s.head_state.receipts[-1].logs = [] self.assertEqual(self.c.totalSupply(), 1) self.assertEqual(self.s.head_state.receipts[-1].logs, []) self.assertEqual(self.c.balanceOf(self.t.a1), 0) self.assertEqual(self.s.head_state.receipts[-1].logs, []) self.assertEqual(self.c.allowance(self.t.a1, self.t.a2), 0) self.assertEqual(self.s.head_state.receipts[-1].logs, []) # Check that failed (Deposit, Withdraw, Transfer) calls emit no events self.assert_tx_failed( lambda: self.c.deposit(value=MAX_UINT256, sender=self.t.k1)) self.assertEqual(self.s.head_state.receipts[-1].logs, []) self.assert_tx_failed(lambda: self.c.withdraw(1, sender=self.t.k1)) self.assertEqual(self.s.head_state.receipts[-1].logs, []) self.assert_tx_failed( lambda: self.c.transfer(self.t.a2, 1, sender=self.t.k1)) self.assertEqual(self.s.head_state.receipts[-1].logs, []) self.assert_tx_failed(lambda: self.c.transferFrom( self.t.a2, self.t.a3, 1, sender=self.t.k1)) self.assertEqual(self.s.head_state.receipts[-1].logs, [])
def test_all(self): self.assertEqual(self.c.totalSupply(), 0, "Token not initially empty") orig_balance0 = self.s.head_state.get_balance(self.t.a0) orig_balance1 = self.s.head_state.get_balance(self.t.a1) self.c.deposit(sender=self.t.k0, value=1000) self.check_logs([log_sigs['Transfer'], 0, bytes_to_int(self.t.a0)], int_to_bytes(1000)) new_balance0 = self.s.head_state.get_balance(self.t.a0) self.assertEqual(self.c.totalSupply(), 1000, "Deposit not working") self.assertEqual(self.c.get_balanceOf(self.t.a0), 1000, "Deposit not working") self.assertEqual(new_balance0, orig_balance0 - 1000, "Deposit did not use funds") self.assertEqual(self.c.get_balanceOf(self.t.a1), 0, "Account balance not empty initially") # If this fails, transfer worked although funds were insufficient self.assert_tx_failed( lambda: self.c.transfer(self.t.a1, 2000, sender=self.t.k0)) self.assertTrue(self.c.transfer(self.t.a1, 500, sender=self.t.k0), "Transfer not working") self.check_logs([ log_sigs['Transfer'], bytes_to_int(self.t.a0), bytes_to_int(self.t.a1) ], int_to_bytes(500)) self.assertEqual(self.c.totalSupply(), 1000, "Transfer changed balance") self.assertEqual(self.c.get_balanceOf(self.t.a0), 500, "Transfer did not remove funds") self.assertEqual(self.c.get_balanceOf(self.t.a1), 500, "Transfer did not add funds") self.assertTrue(self.c.approve(self.t.a0, 200, sender=self.t.k1), "Approval did not work") self.check_logs([ log_sigs['Approval'], bytes_to_int(self.t.a1), bytes_to_int(self.t.a0) ], int_to_bytes(200)) # If this fails, Transfered larger value than approved self.assert_tx_failed(lambda: self.c.transferFrom( self.t.a1, self.t.a0, 201, sender=self.t.k0)) self.assertTrue( self.c.transferFrom(self.t.a1, self.t.a0, 100, sender=self.t.k0), "Transfer not approved") self.check_logs([ log_sigs['Transfer'], bytes_to_int(self.t.a1), bytes_to_int(self.t.a0) ], int_to_bytes(100)) self.assertEqual(self.c.totalSupply(), 1000, "TransferFrom changed balance") self.assertEqual(self.c.balanceOf(self.t.a0), 600, "TransferFrom did not add funds") self.assertEqual(self.c.balanceOf(self.t.a1), 400, "TransferFrom did not remove funds") # Check TransferFrom did not reduce allowance self.assert_tx_failed(lambda: self.c.transferFrom( self.t.a1, self.t.a0, 101, sender=self.t.k0)) # If failed, withdraw more than balance allowed self.assert_tx_failed(lambda: self.c.withdraw(601, sender=self.t.k0)) self.assertTrue(self.c.withdraw(500, sender=self.t.k0), "Withdraw did not work") self.check_logs([log_sigs['Transfer'], bytes_to_int(self.t.a0), 0], int_to_bytes(500)) self.assertEqual(self.c.get_balanceOf(self.t.a0), 100, "Withdraw did not reduce funds") new_balance0 = self.s.head_state.get_balance(self.t.a0) self.assertEqual(new_balance0, orig_balance0 - 500, "Withdraw did not send funds") self.assertEqual(self.c.totalSupply(), 500, "Withdraw did not change balance correctly") self.assertTrue(self.c.withdraw(100, sender=self.t.k0), "Withdraw did not work") self.assertTrue(self.c.withdraw(400, sender=self.t.k1), "Withdraw did not work") self.assertEqual(self.c.totalSupply(), 0, "Token not empty after withdraw") new_balance0 = self.s.head_state.get_balance(self.t.a0) new_balance1 = self.s.head_state.get_balance(self.t.a1) self.assertEqual(new_balance0, orig_balance0 - 400, "Withdraw did not send funds") self.assertEqual(new_balance1, orig_balance1 + 400, "Withdraw did not send funds")
# Author: Florian Tramer import glob import unittest from ethereum import utils from os.path import basename from utils.pyethereum_test_utils import PyEthereumTestCase, bytes_to_int, int_to_bytes # Base path to contracts from current directory PATH_TO_CONTRACTS = "" log_sigs = { 'Transfer': bytes_to_int(utils.sha3("Transfer(address,address,uint256)")), 'Approval': bytes_to_int(utils.sha3("Approval(address,address,uint256)")) } class TestERC20Flo(PyEthereumTestCase): def test_all(self): self.assertEqual(self.c.totalSupply(), 0, "Token not initially empty") orig_balance0 = self.s.head_state.get_balance(self.t.a0) orig_balance1 = self.s.head_state.get_balance(self.t.a1) self.c.deposit(sender=self.t.k0, value=1000) self.check_logs([log_sigs['Transfer'], 0, bytes_to_int(self.t.a0)], int_to_bytes(1000)) new_balance0 = self.s.head_state.get_balance(self.t.a0)