def test_different_offer_grouping(): price_group_precision = 4 offer1 = Offer(100, 0.123501, timestamp.time_plus(1), OfferType.BUY, 123) offer2 = Offer(100, 0.123401, timestamp.time_plus(1), OfferType.BUY, 124) # test group_offers grouped = group_offers([offer1, offer2], price_group_precision=price_group_precision) assert len(grouped) == 2
def test_signing(accounts): timeout = timestamp.time_plus(milliseconds=100) c = Commitment(offer_id=10, offer_hash=keccak(text='offer id'), timeout=timeout, amount=10) c_unsigned = Commitment(offer_id=10, offer_hash=keccak(text='offer id'), timeout=timeout, amount=10) assert c == c_unsigned c.sign(accounts[0].privatekey) assert c.sender == accounts[0].address assert_serialization(c) with pytest.raises(Exception): assert_serialization(c_unsigned) #check hashes: assert c._hash_without_signature == c_unsigned._hash_without_signature assert c.hash != c_unsigned.hash assert c_unsigned.signature is None # check that getting the sender of unsigned 'Signed'-message raises an error with pytest.raises(ObjectSerializationError): c_unsigned_deserialized = Commitment.deserialize(c_unsigned.serialize(c_unsigned)) raised = False try: c_unsigned.sender except SignatureMissingError: raised = True assert raised
def taker_commitment_msg(): seconds_to_timeout = 0.1 timeout = timestamp.time_plus(seconds_to_timeout) offer_id = 123 taker_commitment_msg = messages.Commitment(offer_id=offer_id, offer_hash=keccak(offer_id), timeout=timeout, amount=5) return taker_commitment_msg
def test_swap_completed(accounts): commitment_service = accounts[0] swap_completed_msg = SwapCompleted(big_endian_to_int(keccak(text='offer id')), timestamp.time()) swap_completed_msg.sign(commitment_service.privatekey) time_ = timestamp.time_plus(1) assert_serialization(swap_completed_msg) assert_envelope_serialization(swap_completed_msg) assert swap_completed_msg.sender == commitment_service.address assert time_ > swap_completed_msg.timestamp # should be in the past
def test_swap_execution(accounts): maker = accounts[1] swap_execution_msg = SwapExecution(big_endian_to_int(keccak(text='offer id')), timestamp.time()) swap_execution_msg.sign(maker.privatekey) assert_serialization(swap_execution_msg) assert_envelope_serialization(swap_execution_msg) time_ = timestamp.time_plus(1) assert swap_execution_msg.sender == maker.address assert time_ > swap_execution_msg.timestamp # should be in the past
def create_offer(offer_type, base_amount, quote_amount, offer_lifetime, trader_role): new_offer_id = create_random_32_bytes_id() timeout_date = time_plus(seconds=offer_lifetime) offer_model = Offer(new_offer_id, offer_type, base_amount, quote_amount, timeout_date, trader_role) from raidex.raidex_node.order import fsm_offer fsm_offer.add_model(offer_model) return offer_model
def test_offer_book_task(message_broker, commitment_service, market): offer_book = OfferBook() OfferBookTask(offer_book, market, message_broker).start() gevent.sleep(0.001) offer = OfferDeprecated(OfferType.SELL, 100, 1000, offer_id=123, timeout=timestamp.time_plus(20)) proof = commitment_service.maker_commit_async(offer).get() message_broker.broadcast(proof) gevent.sleep(0.001) assert len(offer_book.sells) == 1
def test_trade_gouping(): price_group_precision = 3 time_group_interval_ms = 100 offer1 = Offer(100, 0.12349, timestamp.time_plus(1), OfferType.BUY, 123) offer2 = Offer(100, 0.12501, timestamp.time_plus(1), OfferType.BUY, 124) # don't work with epoch based timestamps here trade1 = Trade(offer1, timestamp=100) # should be in 100 ms bucket trade2 = Trade( offer1, timestamp=199) # should be in 100 ms bucket, gets grouped with trade1 trade3 = Trade( offer1, timestamp=201) # should be in 200 ms bucket (next highest bucket) trade4 = Trade(offer2, timestamp=201 ) # should be in 200 ms bucket, but not grouped with trade3 def trade_gen_func(from_timestamp=None): return (trade1, trade2, trade3, trade4) grouped = group_trades_from(trade_gen_func, from_timestamp=255, price_group_precision=price_group_precision, time_group_interval=time_group_interval_ms) assert len(grouped) == 3 # grouped is sorted by (timestamp, price) (priority: smaller values) # trade1 and trade 2 combined: assert grouped[0].amount == 200 assert grouped[0].timestamp == 100 # trade3 (same timestamp-bucket as trade4, but smaller price) (BUY): assert grouped[1].amount == 100 assert grouped[1].timestamp == 200 # trade4 (SELL): assert grouped[2].amount == 100 assert grouped[2].timestamp == 200
def test_swap_completed_task(message_broker, commitment_service): trades = TradesView() SwapCompletedTask(trades, message_broker).start() gevent.sleep(0.001) offer = OfferDeprecated(OfferType.SELL, 100, 1000, offer_id=123, timeout=timestamp.time_plus(2)) # set it to pending, as it was taken trades.add_pending(offer) assert len(trades.pending_offer_by_id) == 1 swap_completed = commitment_service.create_swap_completed(offer.offer_id) # send swap_completed message_broker.broadcast(swap_completed) gevent.sleep(0.001) assert len(trades) == 1
def test_taken_task(message_broker, commitment_service): offer_book = OfferBook() trades = TradesView() OfferTakenTask(offer_book, trades, message_broker).start() gevent.sleep(0.001) offer = OfferDeprecated(OfferType.SELL, 100, 1000, offer_id=123, timeout=timestamp.time_plus(2)) # insert manually for the first time offer_book.insert_offer(offer) assert len(offer_book.sells) == 1 offer_taken = commitment_service.create_taken(offer.offer_id) # send offer_taken message_broker.broadcast(offer_taken) gevent.sleep(0.001) assert len(offer_book.sells) == 0 assert len(trades.pending_offer_by_id) == 1
def gen_offer(magic_number, market_price=10.0, max_amount=1000 * ETH, max_deviation=0.01): price = market_price operator = [-1, 1] switch = random.choice((0, 1)) type_ = OfferType(switch) for _ in range(magic_number): drift = random.random() * max_deviation * operator[switch] factor = 1 + drift price *= factor base_amount = random.randint(1, max_amount) quote_amount = int(base_amount * float(price)) assert type_ in (OfferType.BUY, OfferType.SELL) offer = OfferDeprecated(type_, base_amount, quote_amount, # reuse random privkey generation for random offer-ids: big_endian_to_int(make_privkey_address()[0]), # timeout int 10-100 seconds timestamp.time_plus(random.randint(10, 100)) ) return offer
def test_node_to_commitment_service_integration(raidex_nodes, commitment_service): commitment_service.start() [node.start() for node in raidex_nodes] maker_node = raidex_nodes[0] taker_node = raidex_nodes[1] commitment_amount = 5 # this are the initial commitment balances initial_maker_balance = maker_node.trader_client.commitment_balance initial_taker_balance = taker_node.trader_client.commitment_balance initial_commitment_service_balance = commitment_service.trader_client.commitment_balance offer_id = generate_random_offer_id() offer = OfferDeprecated(OfferType.SELL, 100, 1000, offer_id=offer_id, commitment_amount=commitment_amount, timeout=timestamp.time_plus(seconds=0, milliseconds=500)) maker_commit_result = maker_node.commitment_service.maker_commit_async(offer) gevent.sleep(0.01) assert commitment_service.trader_client.commitment_balance == initial_commitment_service_balance + commitment_amount assert maker_node.trader_client.commitment_balance == initial_maker_balance - commitment_amount commitment_service_balance = commitment_service.trader_client.commitment_balance maker_proven_offer = maker_commit_result.get() assert isinstance(maker_proven_offer, messages.ProvenOffer) # CommitmentProof has to be signed by the CS assert maker_proven_offer.commitment_proof.sender == commitment_service.address # ProvenOffer has to be signed by the maker assert maker_proven_offer.sender == maker_node.address # broadcast the ProvenOffer maker_node.message_broker.broadcast(maker_proven_offer) gevent.sleep(0.01) # the taker needs to have the additional commitment-amount information from the ProvenOffer # he should have got it from the broadcasted ProvenOffer taker_internal_offer = taker_node.offer_book.get_offer_by_id(offer.offer_id) taker_commit_result = taker_node.commitment_service.taker_commit_async(taker_internal_offer) gevent.sleep(0.01) assert commitment_service.trader_client.commitment_balance == commitment_service_balance + commitment_amount assert taker_node.trader_client.commitment_balance == initial_taker_balance - commitment_amount taker_proven_commitment = taker_commit_result.get() assert isinstance(taker_proven_commitment, messages.ProvenCommitment) assert taker_proven_commitment.commitment_proof.sender == commitment_service.address assert taker_proven_commitment.sender == taker_node.address maker_node.commitment_service.received_inbound_from_swap(offer.offer_id) taker_node.commitment_service.received_inbound_from_swap(offer.offer_id) gevent.sleep(0.01) # should be processed by the commitment_service, offer_id usable again assert offer_id not in commitment_service.swaps # Check the earnings and refunds assert float_isclose(maker_node.trader_client.commitment_balance, initial_maker_balance - (commitment_amount * commitment_service.fee_rate)) assert float_isclose(taker_node.trader_client.commitment_balance, initial_taker_balance - (commitment_amount * commitment_service.fee_rate)) assert float_isclose(commitment_service.trader_client.commitment_balance, 2 * commitment_amount + 2 * (commitment_amount * commitment_service.fee_rate)) # overall balance shouldn't have changed assert maker_node.trader_client.commitment_balance + taker_node.trader_client.commitment_balance \ + commitment_service.trader_client.commitment_balance == initial_commitment_service_balance \ + initial_taker_balance + initial_maker_balance
def timeout_date(lifetime): return time_plus(seconds=lifetime)