Ejemplo n.º 1
0
def update_iou(
    iou: Dict[str, Any],
    privkey: bytes,
    added_amount: TokenAmount = ZERO_TOKENS,
    expiration_block: Optional[BlockNumber] = None,
) -> Dict[str, Any]:

    expected_signature = to_hex(
        sign_one_to_n_iou(
            privatekey=to_hex(privkey),
            expiration=iou["expiration_block"],
            sender=iou["sender"],
            receiver=iou["receiver"],
            amount=iou["amount"],
        ))
    if iou.get("signature") != expected_signature:
        raise ServiceRequestFailed(
            "Last IOU as given by the pathfinding service is invalid (signature does not match)"
        )

    iou["amount"] += added_amount
    if expiration_block:
        iou["expiration_block"] = expiration_block

    iou["signature"] = to_hex(
        sign_one_to_n_iou(
            privatekey=to_hex(privkey),
            expiration=iou["expiration_block"],
            sender=iou["sender"],
            receiver=iou["receiver"],
            amount=iou["amount"],
        ))

    return iou
Ejemplo n.º 2
0
def update_iou(
    iou: typing.Dict[str, typing.Any],
    privkey: bytes,
    added_amount: typing.TokenAmount = 0,
    expiration_block: typing.Optional[typing.BlockNumber] = None,
) -> typing.Dict[str, typing.Any]:

    expected_signature = to_hex(
        sign_one_to_n_iou(
            privatekey=to_hex(privkey),
            expiration=iou['expiration_block'],
            sender=iou['sender'],
            receiver=iou['receiver'],
            amount=iou['amount'],
        ))
    if iou.get('signature') != expected_signature:
        raise ServiceRequestFailed(
            'Last IOU as given by the pathfinding service is invalid (signature does not match)',
        )

    iou['amount'] += added_amount
    if expiration_block:
        iou['expiration_block'] = expiration_block

    iou['signature'] = sign_one_to_n_iou(
        privatekey=to_hex(privkey),
        expiration=iou['expiration_block'],
        sender=iou['sender'],
        receiver=iou['receiver'],
        amount=iou['amount'],
    )

    return iou
Ejemplo n.º 3
0
def test_get_pfs_iou():
    token_network_address = TokenNetworkAddress(bytes([1] * 20))
    privkey = bytes([2] * 32)
    sender = to_checksum_address(privatekey_to_address(privkey))
    receiver = factories.make_checksum_address()
    with patch('raiden.network.pathfinding.requests.get') as get_mock:
        # No previous IOU
        get_mock.return_value.json.return_value = {'last_iou': None}
        assert get_last_iou('http://example.com', token_network_address,
                            sender, receiver) is None

        # Previous IOU
        iou = dict(sender=sender,
                   receiver=receiver,
                   amount=10,
                   expiration_block=1000)
        iou['signature'] = sign_one_to_n_iou(
            privatekey=encode_hex(privkey),
            sender=sender,
            receiver=receiver,
            amount=iou['amount'],
            expiration=iou['expiration_block'],
        )
        get_mock.return_value.json.return_value = {'last_iou': iou}
        assert get_last_iou('http://example.com', token_network_address,
                            sender, receiver) == iou
Ejemplo n.º 4
0
def test_get_pfs_iou():
    token_network_address = TokenNetworkAddress(bytes([1] * 20))
    privkey = bytes([2] * 32)
    sender = privatekey_to_address(privkey)
    receiver = factories.make_address()
    with patch("raiden.network.pathfinding.requests.get") as get_mock:
        # No previous IOU
        get_mock.return_value.json.return_value = {"last_iou": None}
        assert (get_last_iou("http://example.com", token_network_address,
                             sender, receiver, PRIVKEY) is None)

        # Previous IOU
        iou = dict(sender=sender,
                   receiver=receiver,
                   amount=10,
                   expiration_block=1000)
        iou["signature"] = sign_one_to_n_iou(
            privatekey=encode_hex(privkey),
            sender=to_checksum_address(sender),
            receiver=to_checksum_address(receiver),
            amount=iou["amount"],
            expiration=iou["expiration_block"],
        )
        get_mock.return_value.json.return_value = {"last_iou": iou}
        assert (get_last_iou("http://example.com", token_network_address,
                             sender, receiver, PRIVKEY) == iou)
Ejemplo n.º 5
0
def print_gas_one_to_n(
    one_to_n_contract: Contract,
    deposit_to_udc: Callable,
    get_accounts: Callable,
    get_private_key: Callable,
    web3: Web3,
    print_gas: Callable,
) -> None:
    """ Abusing pytest to print gas cost of OneToN functions """
    (A, B) = get_accounts(2)
    deposit_to_udc(A, 30)

    # happy case
    chain_id = int(web3.version.network)
    amount = 10
    expiration = web3.eth.blockNumber + 2
    signature = sign_one_to_n_iou(
        get_private_key(A),
        sender=A,
        receiver=B,
        amount=amount,
        expiration_block=expiration,
        one_to_n_address=one_to_n_contract.address,
        chain_id=chain_id,
    )
    txn_hash = one_to_n_contract.functions.claim(
        A, B, amount, expiration, one_to_n_contract.address, signature
    ).call_and_transact({"from": A})
    print_gas(txn_hash, CONTRACT_ONE_TO_N + ".claim")
Ejemplo n.º 6
0
def print_gas_one_to_n(
    one_to_n_contract,
    deposit_to_udc,
    get_accounts,
    get_private_key,
    web3,
    print_gas,
):
    """ Abusing pytest to print gas cost of OneToN functions """
    (A, B) = get_accounts(2)
    deposit_to_udc(A, 30)

    # happy case
    amount = 10
    expiration = web3.eth.blockNumber + 2
    signature = sign_one_to_n_iou(
        get_private_key(A),
        sender=A,
        receiver=B,
        amount=amount,
        expiration=expiration,
    )
    txn_hash = one_to_n_contract.functions.claim(
        A,
        B,
        amount,
        expiration,
        signature,
    ).transact({'from': A})
    print_gas(txn_hash, CONTRACT_ONE_TO_N + '.claim')
Ejemplo n.º 7
0
def update_iou(
    iou: IOU,
    privkey: bytes,
    added_amount: TokenAmount = ZERO_TOKENS,
    expiration_block: Optional[BlockNumber] = None,
) -> IOU:

    expected_signature = Signature(
        sign_one_to_n_iou(
            privatekey=to_hex(privkey),
            sender=to_checksum_address(iou.sender),
            receiver=to_checksum_address(iou.receiver),
            amount=iou.amount,
            expiration_block=iou.expiration_block,
            one_to_n_address=to_checksum_address(iou.one_to_n_address),
            chain_id=iou.chain_id,
        ))
    if iou.signature != expected_signature:
        raise ServiceRequestFailed(
            "Last IOU as given by the Pathfinding Service is invalid (signature does not match)"
        )

    iou.amount = TokenAmount(iou.amount + added_amount)
    if expiration_block:
        iou.expiration_block = expiration_block

    iou.sign(privkey)

    return iou
Ejemplo n.º 8
0
def test_claim_by_unregistered_service(
    one_to_n_contract: Contract,
    deposit_to_udc: Callable,
    get_accounts: Callable,
    get_private_key: Callable,
    web3: Web3,
) -> None:
    """OneToN contract should not work for an unregistered service provider."""
    (A, B) = get_accounts(2)
    deposit_to_udc(A, 30)

    amount = 10
    expiration = web3.eth.blockNumber + 2
    chain_id = int(web3.version.network)

    signature = sign_one_to_n_iou(
        get_private_key(A),
        sender=A,
        receiver=B,
        amount=amount,
        expiration_block=expiration,
        one_to_n_address=one_to_n_contract.address,
        chain_id=chain_id,
    )

    # Doesn't work because B is not registered
    with pytest.raises(TransactionFailed, match="receiver not registered"):
        one_to_n_contract.functions.claim(
            sender=A,
            receiver=B,
            amount=amount,
            expiration_block=expiration,
            one_to_n_address=one_to_n_contract.address,
            signature=signature,
        ).call_and_transact({"from": A})
Ejemplo n.º 9
0
def print_gas_one_to_n(
    one_to_n_contract: Contract,
    deposit_to_udc: Callable,
    print_gas: Callable,
    make_iou: Callable,
    web3: Web3,
    get_private_key: Callable,
    create_service_account: Callable,
    create_account: Callable,
) -> None:
    """ Abusing pytest to print gas cost of OneToN functions """
    A = create_account()
    B = create_service_account()
    deposit_to_udc(A, 30)

    # happy case
    chain_id = int(web3.version.network)
    amount = 10
    expiration = web3.eth.blockNumber + 2
    signature = sign_one_to_n_iou(
        get_private_key(A),
        sender=A,
        receiver=B,
        amount=amount,
        expiration_block=expiration,
        one_to_n_address=one_to_n_contract.address,
        chain_id=chain_id,
    )
    txn_hash = one_to_n_contract.functions.claim(
        A, B, amount, expiration, one_to_n_contract.address,
        signature).call_and_transact({"from": A})

    print_gas(txn_hash, CONTRACT_ONE_TO_N + ".claim")

    # bulk claims gas prices
    def concat_iou_data(ious: List[Dict], key: str) -> List:
        return [iou[key] for iou in ious]

    def concat_iou_signatures(ious: List[Dict]) -> bytes:
        result = b""
        for iou in ious:
            result += iou["signature"]

        return result

    for num_ious in (1, 6):
        receivers = [create_service_account() for i in range(num_ious)]
        ious = [make_iou(A, r) for r in receivers]

        txn_hash = one_to_n_contract.functions.bulkClaim(
            concat_iou_data(ious, "sender"),
            concat_iou_data(ious, "receiver"),
            concat_iou_data(ious, "amount"),
            concat_iou_data(ious, "expiration_block"),
            one_to_n_contract.address,
            concat_iou_signatures(ious),
        ).call_and_transact({"from": A})
        print_gas(txn_hash, CONTRACT_ONE_TO_N + f".bulkClaim {num_ious} ious")
Ejemplo n.º 10
0
 def sign(self, privkey: bytes) -> None:
     self.signature = Signature(
         sign_one_to_n_iou(
             privatekey=encode_hex(privkey),
             sender=to_checksum_address(self.sender),
             receiver=to_checksum_address(self.receiver),
             amount=self.amount,
             expiration_block=self.expiration_block,
             one_to_n_address=to_checksum_address(self.one_to_n_address),
             chain_id=self.chain_id,
         ))
Ejemplo n.º 11
0
 def f(
     sender: HexAddress,
     receiver: HexAddress,
     amount: int = 10,
     expiration_block: int = None,
     chain_id: int = chain_id,
     one_to_n_address: HexAddress = one_to_n_contract.address,
 ) -> dict:
     if expiration_block is None:
         expiration_block = web3.eth.blockNumber + 10
     iou = dict(
         sender=sender,
         receiver=receiver,
         amount=amount,
         expiration_block=expiration_block,
         one_to_n_address=one_to_n_address,
         chain_id=chain_id,
     )
     iou["signature"] = sign_one_to_n_iou(get_private_key(sender), **iou)
     del iou["chain_id"]
     return iou
Ejemplo n.º 12
0
def test_update_iou():
    privkey = bytes([2] * 32)
    sender = Address(privatekey_to_address(privkey))
    receiver = Address(bytes([1] * 20))

    # prepare iou
    iou = {
        "sender": encode_hex(sender),
        "receiver": encode_hex(receiver),
        "amount": 10,
        "expiration_block": 1000,
    }
    iou["signature"] = encode_hex(
        sign_one_to_n_iou(
            privatekey=encode_hex(privkey),
            sender=iou["sender"],
            receiver=iou["receiver"],
            amount=iou["amount"],
            expiration=iou["expiration_block"],
        ))

    # update and compare
    added_amount = 10
    new_iou = update_iou(iou=iou.copy(),
                         privkey=privkey,
                         added_amount=added_amount)
    assert new_iou["amount"] == iou["amount"] + added_amount
    assert new_iou["sender"] == iou["sender"]
    assert new_iou["receiver"] == iou["receiver"]
    assert new_iou["signature"] != iou["signature"]

    # Previous IOU with increased amount by evil PFS
    tampered_iou = new_iou.copy()
    tampered_iou["amount"] += 10
    with pytest.raises(ServiceRequestFailed):
        update_iou(iou=tampered_iou,
                   privkey=privkey,
                   added_amount=added_amount)
Ejemplo n.º 13
0
 def f(
     sender_priv_key,
     receiver: Address,
     amount=1,
     expiration_block=MIN_IOU_EXPIRY + 100,
     one_to_n_address=one_to_n_contract.address,
     chain_id=1,
 ) -> IOU:
     receiver_hex: str = to_checksum_address(receiver)
     iou_dict = {
         "sender":
         to_checksum_address(private_key_to_address(sender_priv_key)),
         "receiver": receiver_hex,
         "amount": amount,
         "expiration_block": expiration_block,
         "one_to_n_address": to_checksum_address(one_to_n_address),
         "chain_id": chain_id,
     }
     iou_dict["signature"] = encode_hex(
         sign_one_to_n_iou(privatekey=sender_priv_key, **iou_dict))
     iou = IOU.Schema().load(iou_dict)
     iou.claimed = False
     return iou
Ejemplo n.º 14
0
 def f(
         sender_priv_key: PrivateKey,
         receiver: Address,
         amount=1,
         claimable_until=1000000000 * 15 + MIN_IOU_EXPIRY,
         one_to_n_address: Address = one_to_n_contract_address,
         chain_id: ChainID = ChainID(61),
 ) -> IOU:
     receiver_hex: str = to_checksum_address(receiver)
     iou_dict = {
         "sender":
         to_checksum_address(private_key_to_address(sender_priv_key)),
         "receiver": receiver_hex,
         "amount": amount,
         "claimable_until": claimable_until,
         "one_to_n_address": to_checksum_address(one_to_n_address),
         "chain_id": chain_id,
     }
     iou_dict["signature"] = encode_hex(
         sign_one_to_n_iou(privatekey=sender_priv_key, **iou_dict))
     iou = IOU.Schema().load(iou_dict)
     iou.claimed = False
     return iou
Ejemplo n.º 15
0
def make_iou(
    config: Dict[str, Any],
    our_address: Address,
    one_to_n_address: Address,
    privkey: bytes,
    block_number: BlockNumber,
    chain_id: int,
    offered_fee: TokenAmount = None,
) -> Dict:
    expiration = block_number + config["pathfinding_iou_timeout"]

    iou = dict(
        sender=to_checksum_address(our_address),
        receiver=config["pathfinding_eth_address"],
        amount=offered_fee or config["pathfinding_max_fee"],
        expiration_block=expiration,
        one_to_n_address=to_checksum_address(one_to_n_address),
        chain_id=chain_id,
    )

    iou.update(
        signature=to_hex(sign_one_to_n_iou(privatekey=to_hex(privkey), **iou)))

    return iou
Ejemplo n.º 16
0
def make_iou(
    config: typing.Dict[str, typing.Any],
    our_address: typing.Address,
    privkey: bytes,
    block_number: typing.BlockNumber,
    offered_fee: typing.TokenAmount = None,
) -> typing.Dict:
    expiration = block_number + config['pathfinding_iou_timeout']

    iou = dict(
        sender=to_checksum_address(our_address),
        receiver=config['pathfinding_eth_address'],
        amount=offered_fee or config['pathfinding_max_fee'],
    )

    iou.update(
        expiration_block=expiration,
        signature=to_hex(
            sign_one_to_n_iou(privatekey=to_hex(privkey),
                              expiration=expiration,
                              **iou), ),
    )

    return iou
Ejemplo n.º 17
0
def test_claim(
    user_deposit_contract,
    one_to_n_contract,
    deposit_to_udc,
    get_accounts,
    get_private_key,
    web3,
    event_handler,
):
    ev_handler = event_handler(one_to_n_contract)
    (A, B) = get_accounts(2)
    deposit_to_udc(A, 30)

    # happy case
    amount = 10
    expiration = web3.eth.blockNumber + 2
    signature = sign_one_to_n_iou(
        get_private_key(A),
        sender=A,
        receiver=B,
        amount=amount,
        expiration=expiration,
    )
    tx_hash = one_to_n_contract.functions.claim(
        A,
        B,
        amount,
        expiration,
        signature,
    ).transact({'from': A})

    ev_handler.assert_event(
        tx_hash,
        OneToNEvent.CLAIMED,
        dict(sender=A,
             receiver=B,
             expiration_block=expiration,
             transferred=amount),
    )
    assert user_deposit_contract.functions.balances(A).call() == 20
    assert user_deposit_contract.functions.balances(B).call() == 10

    # can't be claimed twice
    with pytest.raises(TransactionFailed):
        one_to_n_contract.functions.claim(
            A,
            B,
            amount,
            expiration,
            signature,
        ).transact({'from': A})

    # IOU expired
    with pytest.raises(TransactionFailed):
        bad_expiration = web3.eth.blockNumber
        signature = sign_one_to_n_iou(
            get_private_key(A),
            sender=A,
            receiver=B,
            amount=amount,
            expiration=bad_expiration,
        )
        one_to_n_contract.functions.claim(
            A,
            B,
            amount,
            bad_expiration,
            signature,
        ).transact({'from': A})

    # bad signature
    with pytest.raises(TransactionFailed):
        expiration = web3.eth.blockNumber + 1
        signature = sign_one_to_n_iou(
            get_private_key(A),
            sender=A,
            receiver=B,
            amount=amount + 1,  # this does not match amount below
            expiration=expiration,
        )
        one_to_n_contract.functions.claim(
            A,
            B,
            amount,
            expiration,
            signature,
        ).transact({'from': A})
Ejemplo n.º 18
0
def test_claim(
    user_deposit_contract,
    one_to_n_contract,
    deposit_to_udc,
    get_accounts,
    get_private_key,
    web3,
    event_handler,
):
    ev_handler = event_handler(one_to_n_contract)
    (A, B) = get_accounts(2)
    deposit_to_udc(A, 30)

    # happy case
    amount = 10
    expiration = web3.eth.blockNumber + 2
    chain_id = int(web3.version.network)

    # IOU expired
    with pytest.raises(TransactionFailed):
        bad_expiration = web3.eth.blockNumber - 1
        signature = sign_one_to_n_iou(
            get_private_key(A),
            sender=A,
            receiver=B,
            amount=amount,
            expiration_block=bad_expiration,
            one_to_n_address=one_to_n_contract.address,
            chain_id=chain_id,
        )
        one_to_n_contract.functions.claim(A, B, amount, bad_expiration,
                                          one_to_n_contract.address,
                                          signature).call({"from": A})

    # Wrong OneToN address
    with pytest.raises(TransactionFailed):
        signature = sign_one_to_n_iou(
            get_private_key(A),
            sender=A,
            receiver=B,
            amount=amount,
            expiration_block=expiration,
            one_to_n_address=A,  # Inject an error
            chain_id=chain_id,
        )
        one_to_n_contract.functions.claim(A, B, amount, expiration, A,
                                          signature).call({"from": A})

    # Wrong chain_id
    with pytest.raises(TransactionFailed):
        signature = sign_one_to_n_iou(
            get_private_key(A),
            sender=A,
            receiver=B,
            amount=amount,
            expiration_block=expiration,
            one_to_n_address=one_to_n_contract.address,
            chain_id=chain_id + 2,  # Inject an error
        )
        one_to_n_contract.functions.claim(A, B, amount, expiration, A,
                                          signature).call({"from": A})

    # bad signature
    with pytest.raises(TransactionFailed):
        expiration = web3.eth.blockNumber + 1
        signature = sign_one_to_n_iou(
            get_private_key(A),
            sender=A,
            receiver=B,
            amount=amount + 1,  # this does not match amount below
            expiration_block=expiration,
            one_to_n_address=one_to_n_contract.address,
            chain_id=chain_id,
        )
        one_to_n_contract.functions.claim(A, B, amount, expiration,
                                          one_to_n_contract.address,
                                          signature).call({"from": A})

    signature = sign_one_to_n_iou(
        get_private_key(A),
        sender=A,
        receiver=B,
        amount=amount,
        expiration_block=expiration,
        one_to_n_address=one_to_n_contract.address,
        chain_id=chain_id,
    )

    tx_hash = one_to_n_contract.functions.claim(
        sender=A,
        receiver=B,
        amount=amount,
        expiration_block=expiration,
        one_to_n_address=one_to_n_contract.address,
        signature=signature,
    ).call_and_transact({"from": A})

    ev_handler.assert_event(
        tx_hash,
        OneToNEvent.CLAIMED,
        dict(sender=A,
             receiver=B,
             expiration_block=expiration,
             transferred=amount),
    )
    assert user_deposit_contract.functions.balances(A).call() == 20
    assert user_deposit_contract.functions.balances(B).call() == 10

    # can't be claimed twice
    with pytest.raises(TransactionFailed):
        one_to_n_contract.functions.claim(A, B, amount, expiration,
                                          one_to_n_contract.address,
                                          signature).call({"from": A})
Ejemplo n.º 19
0
def test_claim_with_insufficient_deposit(
    user_deposit_contract,
    one_to_n_contract,
    deposit_to_udc,
    get_accounts,
    get_private_key,
    web3,
    event_handler,
):
    ev_handler = event_handler(one_to_n_contract)
    (A, B) = get_accounts(2)
    deposit_to_udc(A, 6)
    chain_id = int(web3.version.network)

    amount = 10
    expiration = web3.eth.blockNumber + 1
    signature = sign_one_to_n_iou(
        get_private_key(A),
        sender=A,
        receiver=B,
        amount=amount,
        expiration_block=expiration,
        one_to_n_address=one_to_n_contract.address,
        chain_id=chain_id,
    )

    # amount is 10, but only 6 are in deposit
    # check return value (transactions don't give back return values, so use call)
    assert (one_to_n_contract.functions.claim(A, B, amount, expiration,
                                              one_to_n_contract.address,
                                              signature).call({"from":
                                                               A}) == 6)
    # check that transaction succeeds
    one_to_n_contract.functions.claim(A, B, amount, expiration,
                                      one_to_n_contract.address,
                                      signature).call_and_transact({"from": A})

    assert user_deposit_contract.functions.balances(A).call() == 0
    assert user_deposit_contract.functions.balances(B).call() == 6

    # claim can be retried when transferred amount was 0
    expiration = web3.eth.blockNumber + 10
    signature = sign_one_to_n_iou(
        get_private_key(A),
        sender=A,
        receiver=B,
        amount=amount,
        expiration_block=expiration,
        one_to_n_address=one_to_n_contract.address,
        chain_id=chain_id,
    )
    one_to_n_contract.functions.claim(A, B, amount, expiration,
                                      one_to_n_contract.address,
                                      signature).call_and_transact({"from": A})
    deposit_to_udc(A, 6 + 4)
    tx_hash = one_to_n_contract.functions.claim(
        A, B, amount, expiration, one_to_n_contract.address,
        signature).call_and_transact({"from": A})
    ev_handler.assert_event(
        tx_hash,
        OneToNEvent.CLAIMED,
        dict(sender=A, receiver=B, expiration_block=expiration, transferred=4),
    )
Ejemplo n.º 20
0
def test_claim_with_insufficient_deposit(
    user_deposit_contract: Contract,
    one_to_n_contract: Contract,
    deposit_to_udc: Callable,
    get_private_key: Callable,
    web3: Web3,
    event_handler: Callable,
    create_account: Callable,
    create_service_account: Callable,
) -> None:
    ev_handler = event_handler(one_to_n_contract)
    A = create_account()
    B = create_service_account()
    deposit_to_udc(A, 6)
    chain_id = web3.eth.chain_id

    amount = TokenAmount(10)
    expiration = BlockExpiration(web3.eth.block_number + 1)
    signature = sign_one_to_n_iou(
        get_private_key(A),
        sender=A,
        receiver=B,
        amount=amount,
        expiration_block=expiration,
        one_to_n_address=one_to_n_contract.address,
        chain_id=ChainID(chain_id),
    )

    # amount is 10, but only 6 are in deposit
    # check return value (transactions don't give back return values, so use call)
    assert (one_to_n_contract.functions.claim(A, B, amount, expiration,
                                              one_to_n_contract.address,
                                              signature).call({"from":
                                                               A}) == 6)
    # check that transaction succeeds
    call_and_transact(
        one_to_n_contract.functions.claim(A, B, amount, expiration,
                                          one_to_n_contract.address,
                                          signature),
        {"from": A},
    )

    assert user_deposit_contract.functions.balances(A).call() == 0
    assert user_deposit_contract.functions.balances(B).call() == 6

    # claim can be retried when transferred amount was 0
    expiration = BlockExpiration(web3.eth.block_number + 10)
    signature = sign_one_to_n_iou(
        get_private_key(A),
        sender=A,
        receiver=B,
        amount=amount,
        expiration_block=expiration,
        one_to_n_address=one_to_n_contract.address,
        chain_id=ChainID(chain_id),
    )
    call_and_transact(
        one_to_n_contract.functions.claim(A, B, amount, expiration,
                                          one_to_n_contract.address,
                                          signature),
        {"from": A},
    )
    deposit_to_udc(A, 6 + 4)
    tx_hash = call_and_transact(
        one_to_n_contract.functions.claim(A, B, amount, expiration,
                                          one_to_n_contract.address,
                                          signature),
        {"from": A},
    )
    ev_handler.assert_event(
        tx_hash,
        OneToNEvent.CLAIMED,
        dict(sender=A, receiver=B, expiration_block=expiration, transferred=4),
    )