Beispiel #1
0
def test_auction_final_bid_5(web3, owner, get_bidders, contract_params,
                             token_contract, auction_contract_fast_decline,
                             auction_bid_tested, auction_end_tests,
                             create_accounts):
    auction = auction_contract_fast_decline
    token = token_contract(auction.address)
    auction.transact({'from': owner}).setup(token.address)
    auction.transact({'from': owner}).startAuction()

    (A, late_bidder, *bidders) = get_bidders(7)

    missing_funds = auction.call().missingFundsToEndAuction()
    amount = missing_funds - 5
    auction_bid_tested(auction, A, amount)

    pre_received_wei = auction.call().received_wei()
    bidded = 0
    for bidder in bidders:
        # Some parameters decrease the price very fast
        missing_funds = auction.call().missingFundsToEndAuction()
        if missing_funds > 0:
            auction_bid_tested(auction, bidder, 1)
            bidded += 1
        else:
            break

    assert auction.call().received_wei() == pre_received_wei + bidded

    auction.transact({'from': owner}).finalizeAuction()
    auction_end_tests(auction, late_bidder)
def test_distributor_init(chain, web3, wallet_address, owner, get_bidders,
                          create_contract, contract_params):
    A = get_bidders(1)[0]
    Distributor = chain.provider.get_contract_factory('Distributor')
    Auction = chain.provider.get_contract_factory('DutchAuction')
    auction = create_contract(Auction,
                              [wallet_address] + contract_params['args'],
                              {'from': owner})

    other_auction_params = [wallet_address] + contract_params['args']
    other_owner_auction = create_contract(Auction, other_auction_params,
                                          {'from': A})
    other_contract_type = create_contract(Distributor, [auction.address])

    assert owner != A

    # Fail if no auction address is provided
    with pytest.raises(TypeError):
        create_contract(Distributor, [])

    # Fail if non address-type auction address is provided
    with pytest.raises(TypeError):
        create_contract(Distributor, [fake_address])
    with pytest.raises(TypeError):
        create_contract(Distributor, [0x0])

    # Fail if auction has another owner
    with pytest.raises(tester.TransactionFailed):
        create_contract(Distributor, [other_owner_auction.address])

    distributor_contract = create_contract(Distributor, [auction.address])
Beispiel #3
0
def test_auction_setup(web3, owner, get_bidders, auction_contract,
                       token_contract, contract_params, event_handler):
    auction = auction_contract
    A = get_bidders(2)[0]
    ev_handler = event_handler(auction)

    assert auction.call().stage() == 0  # AuctionDeployed
    assert auction.call().num_tokens_auctioned() == 0

    # changeSettings is a private method
    with pytest.raises(ValueError):
        auction.transact({'from': owner}).changeSettings(1000, 556, 322)

    web3.testing.mine(5)
    token = token_contract(auction.address)

    txn_hash = auction.transact({'from': owner}).setup(token.address)
    ev_handler.add(txn_hash, 'Setup')
    assert auction.call().num_tokens_auctioned() == token.call().balanceOf(
        auction.address)
    assert auction.call().token_multiplier() == 10**token.call().decimals()
    assert auction.call().stage() == 1

    # Token cannot be changed after setup
    with pytest.raises(tester.TransactionFailed):
        auction.call().setup(token.address)

    ev_handler.check()
Beispiel #4
0
def test_token_allowance(web3, wallet_address, get_bidders, get_token_contract,
                         proxy_contract, decimals):
    (A, B) = get_bidders(2)
    multiplier = 10**(decimals)

    token = get_token_contract(
        [proxy_contract.address, wallet_address, 5000 * multiplier],
        decimals=decimals)
    assert token.call().decimals() == decimals

    token.transact({'from': wallet_address}).transfer(A, 3000)
    token.transact({'from': wallet_address}).transfer(B, 2000)

    with pytest.raises(TypeError):
        token.call().allowance(0, B)

    with pytest.raises(TypeError):
        token.call().allowance(fake_address, B)

    with pytest.raises(TypeError):
        token.call().allowance(A, 0)

    with pytest.raises(TypeError):
        token.call().allowance(A, fake_address)

    assert token.call().allowance(A, B) == 0
    assert token.call().allowance(B, A) == 0

    token.transact({'from': A}).approve(B, 300)
    assert token.call().allowance(A, B) == 300
Beispiel #5
0
def test_token_transfer(chain, web3, wallet_address, get_bidders,
                        get_token_contract, token_contract, proxy_contract,
                        proxy_erc223_contract, decimals, event_handler):
    (A, B, C) = get_bidders(3)
    multiplier = 10**(decimals)

    token = get_token_contract([
        proxy_contract.address,
        wallet_address,
        5000 * multiplier,
    ],
                               decimals=decimals)
    assert token.call().decimals() == decimals

    token.transact({'from': wallet_address}).transfer(A, 3000)
    token.transact({'from': wallet_address}).transfer(B, 2000)
    token.transact({'from': wallet_address}).transfer(C, 1000)

    transfer_tests((A, B, C), [3000, 2000, 1000], multiplier, token,
                   event_handler)

    token_erc223 = token_contract(proxy_erc223_contract.address)
    token_erc223.transact({'from': wallet_address}).transfer(A, 3000)
    token_erc223.transact({'from': wallet_address}).transfer(B, 2000)
    token_erc223.transact({'from': wallet_address}).transfer(C, 1000)

    transfer_erc223_tests((A, B, C), [3000, 2000, 1000], multiplier, token,
                          proxy_contract, token_erc223, proxy_erc223_contract,
                          event_handler)
Beispiel #6
0
def test_auction_final_bid_2(
    web3,
    owner,
    get_bidders,
    contract_params,
    token_contract,
    auction_contract_fast_decline,
    auction_bid_tested,
    auction_end_tests
):
    auction = auction_contract_fast_decline
    token = token_contract(auction.address)
    auction.transact({'from': owner}).setup(token.address)
    auction.transact({'from': owner}).startAuction()

    (A, B, late_bidder) = get_bidders(3)

    missing_funds = auction.call().missingFundsToEndAuction()
    amount = missing_funds - 2
    auction_bid_tested(auction, A, amount)

    with pytest.raises(tester.TransactionFailed):
        auction_bid_tested(auction, B, 3)

    # Some parameters decrease the price very fast
    missing_funds = auction.call().missingFundsToEndAuction()
    if missing_funds > 0:
        auction_bid_tested(auction, B, missing_funds)

    auction.transact({'from': owner}).finalizeAuction()
    auction_end_tests(auction, late_bidder)
Beispiel #7
0
def test_auction_final_bid_1(
    web3,
    owner,
    get_bidders,
    contract_params,
    token_contract,
    auction_contract_fast_decline,
    auction_bid_tested,
    auction_end_tests
):
    auction = auction_contract_fast_decline
    token = token_contract(auction.address)
    auction.transact({'from': owner}).setup(token.address)
    auction.transact({'from': owner}).startAuction()

    (bidder, late_bidder) = get_bidders(2)

    missing_funds = auction.call().missingFundsToEndAuction()
    amount = missing_funds - 1
    auction_bid_tested(auction, bidder, amount)

    # Some parameters decrease the price very fast
    missing_funds = auction.call().missingFundsToEndAuction()
    if missing_funds > 0:
        auction_bid_tested(auction, bidder, 1)

    auction.transact({'from': owner}).finalizeAuction()
    auction_end_tests(auction, late_bidder)
Beispiel #8
0
def test_auction_final_bid_more(
    web3,
    owner,
    get_bidders,
    contract_params,
    token_contract,
    auction_contract_fast_decline,
    auction_bid_tested,
    auction_end_tests
):
    auction = auction_contract_fast_decline
    token = token_contract(auction.address)
    auction.transact({'from': owner}).setup(token.address)
    auction.transact({'from': owner}).startAuction()

    (bidder, late_bidder) = get_bidders(2)

    missing_funds = auction.call().missingFundsToEndAuction()
    amount = missing_funds + 1
    with pytest.raises(tester.TransactionFailed):
        web3.eth.sendTransaction({
            'from': bidder,
            'to': auction.address,
            'value': amount
        })
    with pytest.raises(tester.TransactionFailed):
        auction_bid_tested(auction, bidder, amount)
Beispiel #9
0
def test_auction_start(chain, web3, owner, get_bidders,
                       auction_contract_fast_decline, token_contract,
                       auction_bid_tested, auction_end_tests, event_handler):
    auction = auction_contract_fast_decline
    token = token_contract(auction.address)
    ev_handler = event_handler(auction)
    (A, B) = get_bidders(2)

    # Should not be able to start auction before setup
    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': owner}).startAuction()

    txn_hash = auction.transact({'from': owner}).setup(token.address)
    ev_handler.add(txn_hash, 'Setup')
    assert auction.call().stage() == 1

    token_multiplier = auction.call().token_multiplier()

    # Should not be able to start auction if not owner
    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': A}).startAuction()

    txn_hash = auction.transact({'from': owner}).startAuction()
    receipt = chain.wait.for_receipt(txn_hash)
    timestamp = web3.eth.getBlock(receipt['blockNumber'])['timestamp']
    assert auction.call().stage() == 2
    assert auction.call().start_time() == timestamp
    assert auction.call().start_block() == receipt['blockNumber']
    ev_handler.add(txn_hash, 'AuctionStarted',
                   checkAuctionStartedEvent(timestamp, receipt['blockNumber']))

    # Should not be able to call start auction after it has already started
    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': owner}).startAuction()

    amount = web3.eth.getBalance(A) - 10000000
    missing_funds = auction.call().missingFundsToEndAuction()

    # Fails if amount is > missing_funds
    if (missing_funds < amount):
        with pytest.raises(tester.TransactionFailed):
            auction_bid_tested(auction, A, amount)

    missing_funds = auction.call().missingFundsToEndAuction()
    auction_bid_tested(auction, A, missing_funds)

    # Finalize auction
    assert auction.call().missingFundsToEndAuction() == 0
    txn_hash = auction.transact({'from': owner}).finalizeAuction()
    final_price = auction.call().final_price()
    ev_handler.add(txn_hash, 'AuctionEnded',
                   checkAuctionEndedEvent(final_price))
    auction_end_tests(auction, B)

    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': owner}).startAuction()

    ev_handler.check()
Beispiel #10
0
def test_burn(chain, web3, wallet_address, get_bidders, get_token_contract,
              proxy_contract, decimals, txnCost, event_handler):
    decimals = 18
    eth = web3.eth
    (A, B) = get_bidders(2)
    multiplier = 10**(decimals)
    initial_supply = 5000 * multiplier

    token = get_token_contract(
        [proxy_contract.address, wallet_address, initial_supply],
        decimals=decimals)
    assert token.call().decimals() == decimals

    ev_handler = event_handler(token)

    token.transact({'from': wallet_address}).transfer(A, 3000)
    token.transact({'from': wallet_address}).transfer(B, 2000)

    with pytest.raises(TypeError):
        token.transact({'from': B}).burn(-3)

    with pytest.raises(TypeError):
        token.transact({'from': B}).burn(MAX_UINT + 1)

    with pytest.raises(tester.TransactionFailed):
        token.transact({'from': B}).burn(0)

    with pytest.raises(tester.TransactionFailed):
        token.transact({'from': B}).burn(2000 + 1)

    # Balance should not change besides transaction costs
    tokens_B = token.call().balanceOf(B)
    balance_B = eth.getBalance(B)
    burnt = 250
    txn_hash = token.transact({'from': B}).burn(burnt)
    txn_cost = txnCost(txn_hash)
    ev_handler.add(txn_hash, token_events['burn'])

    assert token.call().totalSupply() == initial_supply - burnt
    assert token.call().balanceOf(B) == tokens_B - burnt
    assert balance_B == eth.getBalance(B) + txn_cost

    tokens_B = token.call().balanceOf(B)
    balance_B = eth.getBalance(B)
    total_supply = token.call().totalSupply()

    txn_hash = token.transact({'from': B}).burn(tokens_B)
    txn_cost = txnCost(txn_hash)

    assert token.call().totalSupply() == total_supply - tokens_B
    assert token.call().balanceOf(B) == 0
    assert balance_B == eth.getBalance(B) + txn_cost

    ev_handler.check()
def test_auction_whitelist(web3, owner, wallet_address, get_bidders,
                           auction_contract, token_contract, contract_params,
                           event_handler):
    eth = web3.eth
    auction = auction_contract
    (A, B, C, D, E, F) = get_bidders(6)

    # Initialize token
    token = token_contract(auction.address)

    assert auction.call().whitelist(A) == False
    assert auction.call().whitelist(B) == False
    assert auction.call().whitelist(C) == False
    assert auction.call().whitelist(D) == False
    assert auction.call().whitelist(E) == False

    # We should be able to whitelist at this point
    auction.transact({'from': owner}).addToWhitelist([A, B])
    assert auction.call().whitelist(A) == True
    assert auction.call().whitelist(B) == True

    auction.transact({'from': owner}).setup(token.address)

    auction.transact({'from': owner}).addToWhitelist([D])
    assert auction.call().whitelist(D) == True

    auction.transact({'from': owner}).startAuction()

    # Bid more than bid_threshold should fail for E
    value = auction.call().bid_threshold() + 1
    with pytest.raises(tester.TransactionFailed):
        eth.sendTransaction({'from': E, 'to': auction.address, 'value': value})

    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': E, "value": value}).bid()

    auction.transact({'from': owner}).addToWhitelist([E])
    assert auction.call().whitelist(E) == True

    # Bid more than bid_threshold should be ok for E
    eth.sendTransaction({'from': E, 'to': auction.address, 'value': value})

    auction.transact({'from': A, "value": value}).bid()

    # Test whitelist removal
    auction.transact({'from': B, "value": value}).bid()
    auction.transact({'from': owner}).removeFromWhitelist([B])
    assert auction.call().whitelist(B) == False

    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': B, "value": value}).bid()
Beispiel #12
0
def test_auction_final_bid_0(web3, owner, get_bidders, contract_params,
                             token_contract, auction_contract_fast_decline,
                             auction_bid_tested, auction_end_tests):
    auction = auction_contract_fast_decline
    token = token_contract(auction.address)
    auction.transact({'from': owner}).setup(token.address)
    auction.transact({'from': owner}).startAuction()

    (bidder, late_bidder) = get_bidders(2)

    missing_funds = auction.call().missingFundsToEndAuction()
    auction_bid_tested(auction, bidder, missing_funds)
    auction.transact({'from': owner}).finalizeAuction()
    auction_end_tests(auction, late_bidder)
Beispiel #13
0
def test_auction_bid(chain, web3, owner, wallet_address, get_bidders,
                     auction_contract_fast_decline, token_contract,
                     contract_params, txnCost, auction_end_tests,
                     auction_claim_tokens_tested):
    eth = web3.eth
    auction = auction_contract_fast_decline
    (A, B) = get_bidders(2)

    # Initialize token
    token = token_contract(auction.address)

    # Try sending funds before auction starts
    with pytest.raises(tester.TransactionFailed):
        eth.sendTransaction({'from': A, 'to': auction.address, 'value': 100})

    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': A, "value": 100}).bid()

    auction.transact({'from': owner}).setup(token.address)
    token_multiplier = auction.call().token_multiplier()

    auction.transact({'from': owner}).startAuction()

    # End auction by bidding the needed amount
    missing_funds = auction.call().missingFundsToEndAuction()

    # Test fallback function
    # 76116 gas cost
    txn_hash = eth.sendTransaction({
        'from': A,
        'to': auction.address,
        'value': 100
    })
    receipt = check_succesful_tx(web3, txn_hash)

    assert auction.call().received_wei() == 100
    assert auction.call().bids(A) == 100

    missing_funds = auction.call().missingFundsToEndAuction()

    # 46528 gas cost
    txn_hash = auction.transact({'from': A, "value": missing_funds}).bid()
    receipt = check_succesful_tx(web3, txn_hash)

    assert auction.call().received_wei() == missing_funds + 100
    assert auction.call().bids(A) == missing_funds + 100

    auction.transact({'from': owner}).finalizeAuction()
    auction_end_tests(auction, B)

    # Any payable transactions should fail now
    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': A, "value": 1}).bid()
    with pytest.raises(tester.TransactionFailed):
        eth.sendTransaction({'from': A, 'to': auction.address, 'value': 1})

    auction_claim_tokens_tested(token, auction, A)

    assert auction.call().stage() == 4  # TokensDistributed

    # Any payable transactions should fail now
    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': A, "value": 100}).bid()
    with pytest.raises(tester.TransactionFailed):
        eth.sendTransaction({'from': A, 'to': auction.address, 'value': 100})
Beispiel #14
0
def test_token_transfer_from(chain, web3, wallet_address, get_bidders,
                             get_token_contract, proxy_contract, decimals,
                             event_handler):
    (A, B, C) = get_bidders(3)
    multiplier = 10**(decimals)

    token = get_token_contract(
        [proxy_contract.address, wallet_address, 5000 * multiplier],
        decimals=decimals)
    assert token.call().decimals() == decimals
    ev_handler = event_handler(token)

    token.transact({'from': wallet_address}).transfer(A, 3000)
    token.transact({'from': wallet_address}).transfer(B, 2000)
    token.transact({'from': wallet_address}).transfer(C, 1000)

    txn_hash = token.transact({'from': B}).approve(A, 300)
    ev_handler.add(txn_hash, token_events['approve'])
    assert token.call().allowance(B, A) == 300

    with pytest.raises(TypeError):
        token.transact({'from': A}).transferFrom(0, C, 10)

    with pytest.raises(TypeError):
        token.transact({'from': A}).transferFrom(B, 0, 10)

    with pytest.raises(TypeError):
        token.transact({'from': A}).transferFrom(fake_address, C, 10)

    with pytest.raises(TypeError):
        token.transact({'from': A}).transferFrom(B, fake_address, 10)

    with pytest.raises(TypeError):
        token.transact({'from': A}).transferFrom(B, C, MAX_UINT + 1)

    with pytest.raises(TypeError):
        token.transact({'from': A}).transferFrom(B, C, -5)

    with pytest.raises(tester.TransactionFailed):
        allowance_B = token.call().allowance(B, A)
        token.transact({'from': A}).transferFrom(B, C, allowance_B + 1)

    # We can allow more than the balance, but we cannot transfer more
    with pytest.raises(tester.TransactionFailed):
        balance_B = token.call().balanceOf(B)
        token.transact({'from': B}).approve(A, balance_B + 10)
        token.transact({'from': A}).transferFrom(B, C, balance_B + 10)

    # Test for overflow
    with pytest.raises(tester.TransactionFailed):
        balance_B = token.call().balanceOf(B)
        overflow = MAX_UINT + 1 - balance_B
        token.transact({'from': B}).approve(A, overflow)
        token.transact({'from': A}).transferFrom(B, C, overflow)

    with pytest.raises(tester.TransactionFailed):
        txn_hash = token.transact({'from': B}).approve(A, 300)

    txn_hash = token.transact({'from': B}).approve(A, 0)
    txn_hash = token.transact({'from': B}).approve(A, 300)
    ev_handler.add(txn_hash, token_events['approve'])
    assert token.call().allowance(B, A) == 300

    balance_A = token.call().balanceOf(A)
    balance_B = token.call().balanceOf(B)
    balance_C = token.call().balanceOf(C)

    txn_hash = token.transact({'from': A}).transferFrom(B, C, 0)
    ev_handler.add(txn_hash, token_events['transfer'])
    assert token.call().balanceOf(A) == balance_A
    assert token.call().balanceOf(B) == balance_B
    assert token.call().balanceOf(C) == balance_C

    txn_hash = token.transact({'from': A}).transferFrom(B, C, 150)
    ev_handler.add(txn_hash, token_events['transfer'])
    assert token.call().balanceOf(A) == balance_A
    assert token.call().balanceOf(B) == balance_B - 150
    assert token.call().balanceOf(C) == balance_C + 150

    ev_handler.check()
Beispiel #15
0
def test_distributor_distribute(chain, web3, wallet_address, owner,
                                get_bidders, create_contract, token_contract,
                                auction_contract_fast_decline,
                                auction_bid_tested,
                                auction_claim_tokens_tested,
                                auction_post_distributed_tests, event_handler):
    bidders = get_bidders(10)
    auction = auction_contract_fast_decline
    token = token_contract(auction.address)
    ev_handler = event_handler(auction)

    auction.transact({'from': owner}).setup(token.address)
    auction.transact({'from': owner}).startAuction()

    Distributor = chain.provider.get_contract_factory('Distributor')
    distributor = create_contract(Distributor, [auction.address])

    collector = ClaimsCollector(auction, token)
    bidders_number = 0

    # Simulate some bids and collect the addresses from the events
    for bidder in bidders[:-1]:
        missing = auction.call().missingFundsToEndAuction()
        balance = web3.eth.getBalance(bidder)
        cap = (balance - 500000) // 1000000000000000000
        amount = min(missing, cap)
        # print('-- BIDDING', bidder, amount, missing, balance, cap)
        if (amount > 0):
            tx_hash = auction_bid_tested(auction, bidder, amount)
            ev_handler.add(tx_hash, 'BidSubmission', collector.add)
            ev_handler.check()
            bidders_number += 1

    missing = auction.call().missingFundsToEndAuction()
    if missing > 0:
        tx_hash = auction_bid_tested(auction, bidders[-1], missing)
        ev_handler.add(tx_hash, 'BidSubmission', collector.add)
        ev_handler.check()
        bidders_number += 1

    assert auction.call().missingFundsToEndAuction() == 0
    auction.transact({'from': owner}).finalizeAuction()

    assert len(collector.addresses) == bidders_number

    end_time = auction.call().end_time()
    elapsed = auction.call().token_claim_waiting_period()
    claim_ok_timestamp = end_time + elapsed + 1

    if claim_ok_timestamp > web3.eth.getBlock('latest')['timestamp']:
        # We cannot claim tokens before waiting period has passed
        with pytest.raises(tester.TransactionFailed):
            distributor.transact({
                'from': owner
            }).distribute(collector.addresses[0:2])

        # Simulate time travel
        web3.testing.timeTravel(claim_ok_timestamp)

    # Send 5 claiming transactions in a single batch to not run out of gas
    safe_distribution_no = 5
    steps = math.ceil(len(collector.addresses) / safe_distribution_no)

    # Call the distributor contract with batches of bidder addresses
    for i in range(0, steps):
        start = i * safe_distribution_no
        end = (i + 1) * safe_distribution_no
        tx_hash = auction_claim_tokens_tested(token, auction,
                                              collector.addresses[start:end],
                                              distributor)
        ev_handler.add(tx_hash, 'ClaimedTokens', collector.verify)
        ev_handler.check()
        # distributor.transact({'from': owner}).distribute(collector.addresses[start:end])

    auction_post_distributed_tests(auction)
def auction_ended(
    web3,
    owner,
    get_bidders,
    token_contract,
    auction_contract_fast_decline,
    auction_bid_tested,
    auction_end_tests):
    eth = web3.eth
    auction = auction_contract_fast_decline
    bidders = get_bidders(10)

    # Initialize token
    token = token_contract(auction.address, {'from': owner})
    auction.transact({'from': owner}).setup(token.address)

    auction.transact({'from': owner}).startAuction()

    # Set maximum amount for a bid - we don't want 1 account draining the auction
    missing_funds = auction.call().missingFundsToEndAuction()
    maxBid = missing_funds / 4

    # Bidders start ordering tokens
    bidders_len = len(bidders) - 1
    bidded = 0  # Total bidded amount
    index = 0  # bidders index

    # Make some bids with 1 wei to be sure we test rounding errors
    auction_bid_tested(auction, bidders[0], 1)
    auction_bid_tested(auction, bidders[1], 1)
    index = 2
    bidded = 2
    approx_bid_txn_cost = 4000000

    while auction.call().missingFundsToEndAuction() > 0:
        if bidders_len < index:
            print('!! Not enough accounts to simulate bidders')

        bidder = bidders[index]

        bidder_balance = eth.getBalance(bidder)
        assert auction.call().bids(bidder) == 0

        missing_funds = auction.call().missingFundsToEndAuction()
        amount = int(min(bidder_balance - approx_bid_txn_cost, maxBid))

        if amount <= missing_funds:
            auction_bid_tested(auction, bidder, amount)
        else:
            # Fail if we bid more than missing_funds
            with pytest.raises(tester.TransactionFailed):
                auction_bid_tested(auction, bidder, amount)

            # Bid exactly the amount needed in order to end the auction
            missing_funds = auction.call().missingFundsToEndAuction()
            amount = missing_funds
            auction_bid_tested(auction, bidder, amount)

        bidded += min(amount, missing_funds)
        index += 1

    print('NO OF BIDDERS', index)
    print('received_wei / bidded', auction.call().received_wei(), bidded)
    assert auction.call().received_wei() == bidded
    auction.transact({'from': owner}).finalizeAuction()
    auction_end_tests(auction, bidders[index])

    return (token, auction)
def test_distributor_distribute(chain, web3, wallet_address, owner,
                                get_bidders, create_contract, token_contract,
                                auction_contract_fast_decline,
                                auction_bid_tested,
                                auction_claim_tokens_tested,
                                auction_post_distributed_tests):
    bidders = get_bidders(10)
    auction = auction_contract_fast_decline
    token = token_contract(auction.address)
    auction.transact({'from': owner}).setup(token.address)
    auction.transact({'from': owner}).startAuction()

    Distributor = chain.provider.get_contract_factory('Distributor')
    distributor = create_contract(Distributor, [auction.address])

    # Retrieve bidder addresses from contract bid events
    def get_bidders_addresses(event):
        address = event['args']['_sender']

        if address not in addresses:
            addresses.append(address)
            values.append(0)
            index = len(addresses) - 1
        else:
            index = addresses.index(address)

        values[index] += event['args']['_amount']

    def verify_claim(event):
        addr = event['args']['_recipient']
        sent_amount = event['args']['_sent_amount']

        # Check for double claiming
        assert addr not in verified_claim
        assert auction.call().bids(addr) == 0
        assert sent_amount == token.call().balanceOf(addr)
        verified_claim.append(address)

    for bidder in bidders:
        missing = auction.call().missingFundsToEndAuction()
        balance = web3.eth.getBalance(bidder)
        amount = min(missing, balance - 500000)
        if (amount > 0):
            print('-- BIDDING', amount, missing, balance)
            auction_bid_tested(auction, bidder, amount)

    assert auction.call().missingFundsToEndAuction() == 0
    auction.transact({'from': owner}).finalizeAuction()

    addresses = []
    values = []
    claimed = []
    verified_claim = []

    handle_logs(contract=auction,
                event='BidSubmission',
                callback=get_bidders_addresses)

    with pytest.raises(tester.TransactionFailed):
        distributor.transact({'from': owner}).distribute(addresses[0:2])

    end_time = auction.call().end_time()
    elapsed = auction.call().token_claim_waiting_period()
    web3.testing.timeTravel(end_time + elapsed + 1)

    # Send 5 claiming transactions in a single batch to not run out of gas
    safe_distribution_no = 5
    steps = math.ceil(len(addresses) / safe_distribution_no)

    # Call the distributor contract with batches of bidder addresses
    for i in range(0, steps):
        start = i * safe_distribution_no
        end = (i + 1) * safe_distribution_no
        auction_claim_tokens_tested(token, auction, addresses[start:end],
                                    distributor)
        # distributor.transact({'from': owner}).distribute(addresses[start:end])

    auction_post_distributed_tests(auction)

    # Verify that a single "ClaimedTokens" event has been issued by the auction contract
    # for each address
    for j in range(0, len(addresses) - 1):
        address = addresses[j]
        assert auction.call().bids(address) == 0

        # check if auction event was triggered for this user
        handle_logs(contract=auction,
                    event='ClaimedTokens',
                    params={'filter': {
                        '_recipient': address
                    }},
                    callback=verify_claim)
Beispiel #18
0
def test_auction_simulation(chain, web3, owner, get_bidders, auction_contract,
                            token_contract, contract_params,
                            auction_bid_tested, auction_end_tests,
                            auction_post_distributed_tests,
                            auction_claim_tokens_tested, create_accounts,
                            txnCost, event_handler):
    eth = web3.eth
    auction = auction_contract
    ev_handler = event_handler(auction)
    bidders = get_bidders(12)

    # Initialize token
    token = token_contract(auction.address)

    # Initial Auction state
    assert auction.call().stage() == 0  # AuctionDeployed
    assert eth.getBalance(auction.address) == 0
    assert auction.call().received_wei() == 0

    # Auction setup without being the owner should fail
    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': bidders[1]}).setup(token.address)

    txn_hash = auction.transact({'from': owner}).setup(token.address)
    ev_handler.add(txn_hash, 'Setup')

    assert auction.call().stage() == 1  # AuctionSetUp

    token_multiplier = auction.call().token_multiplier()

    # We want to revert to these, because we set them in the fixtures
    initial_args = [
        auction.call().price_start(),
        auction.call().price_constant(),
        auction.call().price_exponent()
    ]

    # changeSettings is a private method
    with pytest.raises(ValueError):
        auction.transact({'from': owner}).changeSettings(1000, 556, 322)

    # startAuction without being the owner should fail
    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': bidders[1]}).startAuction()

    auction.transact({'from': owner}).startAuction()
    assert auction.call().stage() == 2  # AuctionStarted

    # transferFundsToToken should fail (private)
    with pytest.raises(ValueError):
        auction.transact({'from': bidders[1]}).transferFundsToToken()

    # finalizeAuction should fail (missing funds not 0)
    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': bidders[1]}).finalizeAuction()
    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': owner}).finalizeAuction()

    # Set maximum amount for a bid - we don't want 1 account draining the auction
    missing_funds = auction.call().missingFundsToEndAuction()
    maxBid = missing_funds / 4

    # TODO Test multiple orders from 1 buyer

    # Bidders start ordering tokens
    bidders_len = len(bidders) - 1
    bidded = 0  # Total bidded amount
    index = 0  # bidders index

    # Make some bids with 1 wei to be sure we test rounding errors
    txn_hash = auction_bid_tested(auction, bidders[0], 1)
    ev_handler.add(txn_hash, 'BidSubmission',
                   checkBidEvent(bidders[0], 1, missing_funds))

    missing_funds = auction.call().missingFundsToEndAuction()
    txn_hash = auction_bid_tested(auction, bidders[1], 1)
    ev_handler.add(txn_hash, 'BidSubmission',
                   checkBidEvent(bidders[1], 1, missing_funds))

    index = 2
    bidded = 2
    approx_bid_txn_cost = 4000000

    while auction.call().missingFundsToEndAuction() > 0:
        if bidders_len < index:
            new_account = create_accounts(1)[0]
            bidders.append(new_account)
            bidders_len += 1
            print('Creating 1 additional bidder account', new_account)

        bidder = bidders[index]

        bidder_balance = eth.getBalance(bidder)
        assert auction.call().bids(bidder) == 0

        missing_funds = auction.call().missingFundsToEndAuction()
        amount = int(min(bidder_balance - approx_bid_txn_cost, maxBid))

        if amount <= missing_funds:
            txn_hash = auction.transact({
                'from': bidder,
                "value": amount
            }).bid()
        else:
            # Fail if we bid more than missing_funds
            with pytest.raises(tester.TransactionFailed):
                auction.transact({'from': bidder, "value": amount}).bid()

            # Bid exactly the amount needed in order to end the auction
            amount = missing_funds
            txn_hash = auction.transact({
                'from': bidder,
                "value": amount
            }).bid()

        assert auction.call().bids(bidder) == amount
        ev_handler.add(txn_hash, 'BidSubmission',
                       checkBidEvent(bidder, amount, missing_funds))

        txn_cost = txnCost(txn_hash)
        post_balance = bidder_balance - amount - txn_cost
        bidded += min(amount, missing_funds)

        assert eth.getBalance(bidder) == post_balance
        index += 1

    print('NO OF BIDDERS', index)

    # Auction ended, no more orders possible
    if bidders_len < index:
        print(
            '!! Not enough accounts to simulate bidders. 1 additional account needed'
        )

    # Finalize Auction
    txn_hash = auction.transact({'from': owner}).finalizeAuction()

    # Final price per TKN (Tei * token_multiplier)
    final_price = auction.call().final_price()

    # Make sure events are issued correctly
    ev_handler.add(txn_hash, 'AuctionEnded',
                   checkAuctionEndedEvent(final_price))

    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': owner}).finalizeAuction()

    assert auction.call().received_wei() == bidded
    auction_end_tests(auction, bidders[index])

    # Claim all tokens

    funds_at_price = auction.call().num_tokens_auctioned(
    ) * final_price // token_multiplier
    received_wei = auction.call().received_wei()
    # FIXME sometimes: assert 5000000002 == 5000000000
    assert received_wei == funds_at_price

    # Total Tei claimable
    total_tokens_claimable = auction.call().received_wei(
    ) * token_multiplier // final_price
    print('FINAL PRICE', final_price)
    print('TOTAL TOKENS CLAIMABLE', int(total_tokens_claimable))
    # FIXME assert 5000000002000000000000000 == 5000000000000000000000000
    assert int(total_tokens_claimable) == auction.call().num_tokens_auctioned()

    rounding_error_tokens = 0

    end_time = auction.call().end_time()
    elapsed = auction.call().token_claim_waiting_period()
    claim_ok_timestamp = end_time + elapsed + 1

    # We cannot claim tokens before waiting period has passed
    if claim_ok_timestamp > web3.eth.getBlock('latest')['timestamp']:
        with pytest.raises(tester.TransactionFailed):
            auction_claim_tokens_tested(token, auction, bidders[0])

        # Simulate time travel
        web3.testing.timeTravel(claim_ok_timestamp)

    for i in range(0, index):
        bidder = bidders[i]

        tokens_expected = token_multiplier * auction.call().bids(
            bidder) // final_price
        txn_hash = auction_claim_tokens_tested(token, auction, bidder)

        ev_handler.add(txn_hash, 'ClaimedTokens',
                       checkClaimedTokensEvent(bidder, tokens_expected))

        # If auction funds not transferred to owner (last claimTokens)
        # we test for a correct claimed tokens calculation
        balance_auction = auction.call().received_wei()
        if balance_auction > 0:

            # Auction supply = unclaimed tokens, including rounding errors
            unclaimed_token_supply = token.call().balanceOf(auction.address)

            # Calculated unclaimed tokens
            unclaimed_funds = balance_auction - auction.call().funds_claimed()
            unclaimed_tokens = token_multiplier * unclaimed_funds // auction.call(
            ).final_price()

            # Adding previous rounding errors
            unclaimed_tokens += rounding_error_tokens

            # Token's auction balance should be the same as
            # the unclaimed tokens calculation based on the final_price
            # We assume a rounding error of 1
            if unclaimed_token_supply != unclaimed_tokens:
                rounding_error_tokens += 1
                unclaimed_tokens += 1

            # FIXME assert 4999999999000000000000000 == 5000000001000000000000001
            assert unclaimed_token_supply == unclaimed_tokens

    # Auction balance might be > 0 due to rounding errors
    assert token.call().balanceOf(auction.address) == rounding_error_tokens
    print('FINAL UNCLAIMED TOKENS', rounding_error_tokens)

    # Last claimTokens also triggers a TokensDistributed event
    ev_handler.add(txn_hash, 'TokensDistributed')

    auction_post_distributed_tests(auction)

    # Check if all registered events have been triggered
    ev_handler.check()
def test_auction_bid_from_gnosis_multisig(
    web3,
    owner,
    wallet_address,
    gnosis_multisig_wallet,
    get_bidders,
    auction_contract_fast_decline,
    token_contract,
    event_handler):
    eth = web3.eth
    auction = auction_contract_fast_decline
    (A, B, C) = get_bidders(3)

    # Initialize token
    token = token_contract(auction.address)
    auction.transact({'from': owner}).setup(token.address)
    auction.transact({'from': owner}).startAuction()

    gnosis_wallet1 = gnosis_multisig_wallet([A, B, C], 1)
    gnosis_wallet2 = gnosis_multisig_wallet([A, B, C], 2)

    gnosis_wallet1_balance = 100000
    gnosis_wallet2_balance = 200000

    web3.eth.sendTransaction({
        'from': B,
        'to': gnosis_wallet1.address,
        'value': gnosis_wallet1_balance
    })
    web3.eth.sendTransaction({
        'from': B,
        'to': gnosis_wallet2.address,
        'value': gnosis_wallet2_balance
    })

    # Test gnosis wallet with 2 owners and 1 confirmation
    # Using Auction's fallback function
    pre_balance_wallet = web3.eth.getBalance(wallet_address)
    gnosis_wallet1.transact({'from': A}).submitTransaction(auction.address, 1000, bytearray())

    gnosis_wallet1_balance -= 1000
    assert web3.eth.getBalance(gnosis_wallet1.address) == gnosis_wallet1_balance
    assert auction.call().bids(gnosis_wallet1.address) == 1000
    assert web3.eth.getBalance(wallet_address) == pre_balance_wallet + 1000

    # Test gnosis wallet with 2 owners and 1 confirmation
    # Using Auction's bid() function
    pre_balance_wallet = web3.eth.getBalance(wallet_address)
    data = function_signature_to_4byte_selector('bid()')
    gnosis_wallet1.transact({'from': A}).submitTransaction(auction.address, 1000, data)

    gnosis_wallet1_balance -= 1000
    assert web3.eth.getBalance(gnosis_wallet1.address) == gnosis_wallet1_balance
    assert auction.call().bids(gnosis_wallet1.address) == 2000
    assert web3.eth.getBalance(wallet_address) == pre_balance_wallet + 1000

    transaction_id_keeper = TransactionIdKeeper()

    # Test gnosis wallet with 3 owners and 2 confirmations
    # Using Auction's fallback function
    pre_balance_wallet = web3.eth.getBalance(wallet_address)
    txhash = gnosis_wallet2.transact({'from': A}).submitTransaction(auction.address, 3000, bytearray())
    assert web3.eth.getBalance(gnosis_wallet2.address) == gnosis_wallet2_balance
    assert auction.call().bids(gnosis_wallet2.address) == 0
    assert web3.eth.getBalance(wallet_address) == pre_balance_wallet

    # Wait for transactionId from the Confirmation event
    ev_handler = event_handler(gnosis_wallet2)
    ev_handler.add(txhash, 'Confirmation', transaction_id_keeper.add)
    ev_handler.check()

    # Second owner confirms the transaction
    transaction_id = transaction_id_keeper.transaction_id
    gnosis_wallet2.transact({'from': B}).confirmTransaction(transaction_id)
    gnosis_wallet2_balance -= 3000
    assert web3.eth.getBalance(gnosis_wallet2.address) == gnosis_wallet2_balance
    assert auction.call().bids(gnosis_wallet2.address) == 3000
    assert web3.eth.getBalance(wallet_address) == pre_balance_wallet + 3000

    # Test gnosis wallet with 3 owners and 2 confirmations
    # Using Auction's bid() function
    pre_balance_wallet = web3.eth.getBalance(wallet_address)
    data = function_signature_to_4byte_selector('bid()')
    txhash1 = gnosis_wallet2.transact({'from': A}).submitTransaction(auction.address, 3000, data)

    # Second owner confirms the transaction
    ev_handler.add(txhash1, 'Confirmation', transaction_id_keeper.add)
    ev_handler.check()
    transaction_id = transaction_id_keeper.transaction_id
    gnosis_wallet2.transact({'from': B}).confirmTransaction(transaction_id)

    gnosis_wallet2_balance -= 3000
    assert web3.eth.getBalance(gnosis_wallet2.address) == gnosis_wallet2_balance
    assert auction.call().bids(gnosis_wallet2.address) == 6000
    assert web3.eth.getBalance(wallet_address) == pre_balance_wallet + 3000
Beispiel #20
0
def test_auction_bid(chain, web3, owner, wallet_address, get_bidders,
                     auction_contract_fast_decline, token_contract,
                     contract_params, txnCost, auction_end_tests,
                     auction_claim_tokens_tested, event_handler):
    eth = web3.eth
    auction = auction_contract_fast_decline
    ev_handler = event_handler(auction)
    (A, B) = get_bidders(2)

    # Initialize token
    token = token_contract(auction.address)

    # Try sending funds before auction starts
    with pytest.raises(tester.TransactionFailed):
        eth.sendTransaction({'from': A, 'to': auction.address, 'value': 100})

    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': A, "value": 100}).bid()

    txn_hash = auction.transact({'from': owner}).setup(token.address)
    ev_handler.add(txn_hash, 'Setup')

    token_multiplier = auction.call().token_multiplier()

    txn_hash = auction.transact({'from': owner}).startAuction()
    ev_handler.add(txn_hash, 'AuctionStarted')

    missing_funds = auction.call().missingFundsToEndAuction()

    # Test fallback function
    # 76116 gas cost
    txn_hash = eth.sendTransaction({
        'from': A,
        'to': auction.address,
        'value': 100
    })
    ev_handler.add(txn_hash, 'BidSubmission',
                   checkBidEvent(A, 100, missing_funds))

    assert auction.call().received_wei() == 100
    assert auction.call().bids(A) == 100

    # End auction by bidding the needed amount
    missing_funds = auction.call().missingFundsToEndAuction()

    # 46528 gas cost
    txn_hash2 = auction.transact({'from': A, "value": missing_funds}).bid()
    ev_handler.add(txn_hash2, 'BidSubmission',
                   checkBidEvent(A, missing_funds, missing_funds))

    assert auction.call().received_wei() == missing_funds + 100
    assert auction.call().bids(A) == missing_funds + 100

    auction.transact({'from': owner}).finalizeAuction()
    auction_end_tests(auction, B)

    # Any payable transactions should fail now
    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': A, "value": 1}).bid()
    with pytest.raises(tester.TransactionFailed):
        eth.sendTransaction({'from': A, 'to': auction.address, 'value': 1})

    end_time = auction.call().end_time()
    elapsed = auction.call().token_claim_waiting_period()
    claim_ok_timestamp = end_time + elapsed + 1

    # We cannot claim tokens before waiting period has passed
    if claim_ok_timestamp > web3.eth.getBlock('latest')['timestamp']:
        with pytest.raises(tester.TransactionFailed):
            auction_claim_tokens_tested(token, auction, A)

        # Simulate time travel
        web3.testing.timeTravel(claim_ok_timestamp)

    auction_claim_tokens_tested(token, auction, A)

    assert auction.call().stage() == 4  # TokensDistributed

    # Any payable transactions should fail now
    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': A, "value": 100}).bid()
    with pytest.raises(tester.TransactionFailed):
        eth.sendTransaction({'from': A, 'to': auction.address, 'value': 100})

    ev_handler.check()
Beispiel #21
0
def test_auction_bid_from_multisig(web3, owner, wallet_address,
                                   gnosis_multisig_wallet, get_bidders,
                                   auction_contract_fast_decline,
                                   token_contract, event_handler):
    eth = web3.eth
    auction = auction_contract_fast_decline
    (A, B, C) = get_bidders(3)

    # Initialize token
    token = token_contract(auction.address)
    auction.transact({'from': owner}).setup(token.address)
    auction.transact({'from': owner}).startAuction()

    gnosis_wallet1 = gnosis_multisig_wallet([A, B, C], 1)
    gnosis_wallet2 = gnosis_multisig_wallet([A, B, C], 2)

    web3.eth.sendTransaction({
        'from': B,
        'to': gnosis_wallet1.address,
        'value': 100000
    })
    web3.eth.sendTransaction({
        'from': B,
        'to': gnosis_wallet2.address,
        'value': 200000
    })

    pre_balance_wallet = web3.eth.getBalance(wallet_address)

    # Test gnosis wallet with 2 owners and 1 confirmation
    gnosis_wallet1.transact({
        'from': A
    }).submitTransaction(auction.address, 1000, bytearray())
    assert web3.eth.getBalance(gnosis_wallet1.address) == 100000 - 1000
    assert auction.call().bids(gnosis_wallet1.address) == 1000
    assert web3.eth.getBalance(wallet_address) == pre_balance_wallet + 1000

    transactionId = None

    def setId(event):
        nonlocal transactionId
        transactionId = event['args']['transactionId']

    # Test gnosis wallet with 3 owners and 2 confirmations
    pre_balance_wallet = web3.eth.getBalance(wallet_address)
    txhash = gnosis_wallet2.transact({
        'from': A
    }).submitTransaction(auction.address, 3000, bytearray())
    assert web3.eth.getBalance(gnosis_wallet2.address) == 200000
    assert auction.call().bids(gnosis_wallet2.address) == 0
    assert web3.eth.getBalance(wallet_address) == pre_balance_wallet

    # Wait for transactionId from the Confirmation event
    ev_handler = event_handler(gnosis_wallet2)
    ev_handler.add(txhash, 'Confirmation', setId)
    ev_handler.check()

    # Second owner confirms the transaction
    gnosis_wallet2.transact({'from': B}).confirmTransaction(transactionId)
    assert web3.eth.getBalance(gnosis_wallet2.address) == 200000 - 3000
    assert auction.call().bids(gnosis_wallet2.address) == 3000
    assert web3.eth.getBalance(wallet_address) == pre_balance_wallet + 3000
Beispiel #22
0
def test_auction_whitelist(
    chain,
    web3,
    owner,
    wallet_address,
    whitelister_address,
    get_bidders,
    create_contract,
    token_contract,
    contract_params,
    event_handler):
    eth = web3.eth
    (A, B, C, D, E, F) = get_bidders(6)

    Auction = chain.provider.get_contract_factory('DutchAuction')
    args = [wallet_address, whitelister_address, 2 * 10 ** 18, 1574640000, 3]
    auction = create_contract(Auction, args, {'from': owner})

    # Initialize token
    token = token_contract(auction.address)
    bid_threshold = auction.call().bid_threshold()

    assert auction.call().whitelist(A) == False
    assert auction.call().whitelist(B) == False
    assert auction.call().whitelist(C) == False
    assert auction.call().whitelist(D) == False
    assert auction.call().whitelist(E) == False

    # Only the whitelister_address can add addresses to the whitelist
    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': owner}).addToWhitelist([A, B])
    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': wallet_address}).addToWhitelist([A, B])
    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': A}).addToWhitelist([A, B])
    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': C}).addToWhitelist([A, B])

    # We should be able to whitelist at this point
    auction.transact({'from': whitelister_address}).addToWhitelist([A, B])
    assert auction.call().whitelist(A) == True
    assert auction.call().whitelist(B) == True

    auction.transact({'from': owner}).setup(token.address)

    auction.transact({'from': whitelister_address}).addToWhitelist([D])
    assert auction.call().whitelist(D) == True

    auction.transact({'from': owner}).startAuction()

    # Bid more than bid_threshold should fail for E
    value = bid_threshold + 1
    with pytest.raises(tester.TransactionFailed):
        eth.sendTransaction({
            'from': E,
            'to': auction.address,
            'value': value
        })

    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': E, "value": value}).bid()

    auction.transact({'from': whitelister_address}).addToWhitelist([E])
    assert auction.call().whitelist(E) == True

    print('--- web3.eth.getBalance(E)-- ', web3.eth.getBalance(E))
    print('--- value                 -- ', value)
    print('--- bids                  -- ', auction.call().bids(E))
    assert web3.eth.getBalance(E) > value

    # Bid more than bid_threshold should be ok for E
    eth.sendTransaction({
        'from': E,
        'to': auction.address,
        'value': value
    })

    auction.transact({'from': A, "value": value}).bid()

    # Test whitelist removal
    auction.transact({'from': B, "value": value}).bid()

    # Only the whitelister_address can add addresses to the whitelist
    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': owner}).removeFromWhitelist([B])
    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': wallet_address}).removeFromWhitelist([B])
    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': A}).removeFromWhitelist([B])
    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': C}).removeFromWhitelist([B])

    auction.transact({'from': whitelister_address}).removeFromWhitelist([B])
    assert auction.call().whitelist(B) == False

    with pytest.raises(tester.TransactionFailed):
        auction.transact({'from': B, "value": value}).bid()