forked from defi-wonderland/aztec-standards
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcancel_authwit.nr
More file actions
94 lines (80 loc) · 3.48 KB
/
Copy pathcancel_authwit.nr
File metadata and controls
94 lines (80 loc) · 3.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use crate::NFT;
use crate::test::utils;
use aztec::authwit::auth::compute_inner_authwit_hash;
use aztec::hash::hash_args;
use aztec::protocol::traits::ToField;
use aztec::test::helpers::authwit as authwit_cheatcodes;
use generic_proxy::GenericProxy;
// Proves that once `owner` cancels a private authwit, a caller holding it can no longer consume it:
// the cancellation pre-emits the authwit nullifier, so the later authwit-gated transfer fails when
// it tries to emit the same nullifier again.
#[test(should_fail_with = "duplicate nullifiers")]
unconstrained fn cancelled_authwit_cannot_be_consumed() {
let token_id = 1;
let (mut env, nft_contract_address, owner, _minter, recipient, proxy) =
utils::setup_and_mint_to_private_with_proxy(token_id);
let transfer_call =
NFT::at(nft_contract_address).transfer_private_to_private(owner, recipient, token_id, 1);
authwit_cheatcodes::add_private_authwit_from_call(env, owner, proxy, transfer_call);
let inner_hash = compute_inner_authwit_hash([
proxy.to_field(),
transfer_call.selector.to_field(),
hash_args(transfer_call.args),
]);
env.call_private(owner, NFT::at(nft_contract_address).cancel_authwit(inner_hash));
env.call_private(
owner,
GenericProxy::at(proxy).forward_private_4(
transfer_call.target_contract,
transfer_call.selector,
transfer_call.args,
),
);
}
// Positive control: the same flow WITHOUT the cancel succeeds, attributing the failure above to the
// cancellation.
#[test]
unconstrained fn uncancelled_authwit_is_consumed() {
let token_id = 1;
let (mut env, nft_contract_address, owner, _minter, recipient, proxy) =
utils::setup_and_mint_to_private_with_proxy(token_id);
let transfer_call =
NFT::at(nft_contract_address).transfer_private_to_private(owner, recipient, token_id, 1);
authwit_cheatcodes::add_private_authwit_from_call(env, owner, proxy, transfer_call);
env.call_private(
owner,
GenericProxy::at(proxy).forward_private_4(
transfer_call.target_contract,
transfer_call.selector,
transfer_call.args,
),
);
utils::assert_owns_private_nft(env, nft_contract_address, recipient, token_id);
}
// Caller isolation: a foreign account cancelling with the owner's exact inner hash does NOT revoke
// the owner's authwit — the nullifier is bound to `msg_sender`.
#[test]
unconstrained fn foreign_cancel_does_not_revoke_owner_authwit() {
let token_id = 1;
let (mut env, nft_contract_address, owner, _minter, recipient, proxy) =
utils::setup_and_mint_to_private_with_proxy(token_id);
let transfer_call =
NFT::at(nft_contract_address).transfer_private_to_private(owner, recipient, token_id, 1);
authwit_cheatcodes::add_private_authwit_from_call(env, owner, proxy, transfer_call);
let inner_hash = compute_inner_authwit_hash([
proxy.to_field(),
transfer_call.selector.to_field(),
hash_args(transfer_call.args),
]);
// `recipient` (not the granter) attempts to cancel the owner's authwit
env.call_private(recipient, NFT::at(nft_contract_address).cancel_authwit(inner_hash));
env.call_private(
owner,
GenericProxy::at(proxy).forward_private_4(
transfer_call.target_contract,
transfer_call.selector,
transfer_call.args,
),
);
utils::assert_owns_private_nft(env, nft_contract_address, recipient, token_id);
}