From 684e95091850ba850b47224150016e67a7802a05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 6 Aug 2024 17:50:24 -0300 Subject: [PATCH] feat: make token transfer be recursive (#7730) Replaces https://github.com/AztecProtocol/aztec-packages/pull/7271 Closes https://github.com/AztecProtocol/aztec-packages/issues/7142 Closes https://github.com/AztecProtocol/aztec-packages/issues/7362 This is quite similar to the implementation in #7271: `transfer` consumes two notes, and if their amount is insufficient for the desired transfer it calls a second internal function which recursively consumes 8 notes per iteration until either the amount is reached, or no more notes are found. If the total amount consumed exceeds the transfer amount, a change note is created. This results in a much smaller transfer function for the scenario in which two notes suffice, since we're using a `limit` value of 2 and therefore only doing two iterations of note constraining (the expensive part). Two notes is a good amount as it provides a way for change notes to be consumed in follow-up calls. The recursive call has a much lower gate count, since it doesn't need to fetch keys, create notes, emit events, etc., and so we can afford to read more notes here while still resulting in a relatively small circuit. I created a new e2e test in which the number of notes and their amounts are quite controlled in order to properly test this. The tests are unfortunately currently interdependent, but given the relative simplicity of the test suite it should be hopefully simple to maintain and expand, and maybe eventually fix. --- value-note/src/filter.nr | 2 ++ 1 file changed, 2 insertions(+) diff --git a/value-note/src/filter.nr b/value-note/src/filter.nr index af5b3ee0..8024414d 100644 --- a/value-note/src/filter.nr +++ b/value-note/src/filter.nr @@ -6,6 +6,7 @@ pub fn filter_notes_min_sum( min_sum: Field ) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] { let mut selected = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; + let mut sum = U128::from_integer(0); for i in 0..notes.len() { if notes[i].is_some() & (sum < U128::from_integer(min_sum)) { @@ -14,5 +15,6 @@ pub fn filter_notes_min_sum( sum += U128::from_integer(note.value); } } + selected }