# RFC: Simplifying Token Transfer Mechanisms by Removing Shielding

**URL:** <https://forum.aztec.network/t/rfc-simplifying-token-transfer-mechanisms-by-removing-shielding/6101>\
**Category:** Aztec\
**Tags:** rfc\
**Created:** [August 10, 2024, 8:31pm UTC](https://forum.aztec.network/t/rfc-simplifying-token-transfer-mechanisms-by-removing-shielding/6101 "2024-08-10T20:31:58Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![oleh](https://dub1.discourse-cdn.com/flex013/user_avatar/forum.aztec.network/oleh/32/919_2.png) [@oleh](https://forum.aztec.network/u/oleh)\
**Post date:** [August 10, 2024, 8:31pm UTC](https://forum.aztec.network/t/rfc-simplifying-token-transfer-mechanisms-by-removing-shielding/6101/1 "2024-08-10T20:31:58Z")

</div>

**Authors:** oleh [oleh.blockchain@gmail.com](mailto:oleh.blockchain@gmail.com)  
**Created:** 2024-08-10

## Abstract

This RFC proposes eliminating the `shield`, `unshield`, and `redeem_shield` methods from the token transfer system, replacing them with more intuitive methods: `transfer_from_public_to_private` and `transfer_from_private_to_public`. The changes aim to reduce redundancy, simplify the codebase, and make the token transfer process more understandable for developers.

## Background

Currently, the token contract includes two distinct mechanisms for transferring tokens:

1. **Direct Transfers:**

2. **Shielded Transfers:**

While direct transfers are straightforward and essential, the shielded transfer mechanism introduces redundancy and potential confusion.

## Problem Statement

The existence of two separate mechanisms for transferring tokens (`transfer`/`transfer_public` and `shield`/`redeem_shield`) is redundant. The `redeem_shield` function, in particular, is nearly identical to the `transfer` method, with the only difference being the use of a `secret` instead of the `from` address. This redundancy complicates the token transfer logic and could confuse developers.

## Proposal

To simplify the token transfer system and remove redundancy, the following changes are proposed:

1. **Rename `shield` to `transfer_from_public_to_private`:**

2. **Remove `redeem_shield`:**

3. **Rename `unshield` to `transfer_from_private_to_public`:**

## Implementation

```diff
contract Token {
    #[aztec(storage)]
    struct Storage {
        // ...
- pending_shields: PrivateSet<TransparentNote>,
    }

- #[aztec(public)]
- fn shield(from: AztecAddress, amount: Field, secret_hash: Field, nonce: Field) {
- // removed
- }

+ #[aztec(public)]
+ fn transfer_from_public_to_private(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) {
+ storage.public_balances.get(from).sub(amount);
+ storage.balances.add(to, amount);
+ }

- #[aztec(private)]
- fn redeem_shield(to: AztecAddress, amount: Field, secret: Field) {
- // removed
- }

    #[aztec(private)]
- fn unshield(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) {
+ fn transfer_from_private_to_public(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) {
        // implementation is the same
    }
}

```

This refactor simplifies the token contract by removing the concept of shielding, reducing the number of methods developers need to learn, and consolidating the transfer logic.

## Example Usage

Below is a comparison of how the token transfer functionality is used in JavaScript:

**Before:**

```javascript
const [bobSecret, bobSecretHash] = await generateSecretAndHash();
await token.withWallet(alice).shield(alice, amount, bobSecretHash);
await token.withWallet(bob).redeem_shield(bob, amount, bobSecret);

```

**After the proposed changes:**

```javascript
const bobBurner = await bob.createBurnerAccount();
await token.withWallet(alice).transfer_from_public_to_private(alice, bobBurner, amount);
await token.withWallet(bobBurner).createAuthWit({ caller: bob, action: token.transfer(bobBurner, bob, amount).request() });
await token.withWallet(bob).transfer(bobBurner, bob, amount);

```

The updated JavaScript code is more unified due to the consistent use of transfer methods. Instead of managing secrets and hashes, developers now work with burner accounts, using clear and consistent transfer terminology throughout the process.

## Pros & Cons

### Pros

- **Simplicity:** The token transfer mechanism is streamlined, with fewer concepts and methods to understand.
- **Elimination of Redundancy:** The `secret` and `secret_hash` logic, as well as the `pending_shields` and `TransparentNote` structures, are no longer necessary.
- **Clarity:** Developers can more easily grasp the token transfer process, as there is only one transfer mechanism to learn.

### Cons

- **Privacy Risks:** Transferring tokens from a public to a private address could expose privacy risks if the destination is a main account rather than a burner account. The previous shielding process made it clear that tokens were being shielded for privacy, which may not be as obvious with the new approach.
- Needs an additional `.createAuthWit(...)` call on JS side.

## Open Questions

1. How does `transfer(burner_address, to, amount)` compare to `redeem_shield(to, amount, secret)` in terms of constraints used, assuming that the `amount` is represented as a single note.
2. Can the call to `.createAuthWit(...)` be avoided on JS side?

## Conclusion

This RFC recommends simplifying the token contract by removing the shielding mechanism and replacing it with a more intuitive transfer method. By doing so, the token transfer process will become more straightforward, reducing the cognitive load on developers and improving overall system clarity.

---

<div class="post-metadata">

**Author:** ![joshc](https://dub1.discourse-cdn.com/flex013/user_avatar/forum.aztec.network/joshc/32/20_2.png) [@joshc](https://forum.aztec.network/u/joshc)\
**Post date:** [August 14, 2024, 2:54pm UTC](https://forum.aztec.network/t/rfc-simplifying-token-transfer-mechanisms-by-removing-shielding/6101/2 "2024-08-14T14:54:05Z")

</div>

I am not sure that this will work. It looks like you are adding to a private storage variable (`balances`) from a public function (`transfer_from_public_to_private`), which won’t work.

You could remove `redeem_shield` with something like:

```rust
private fn shield(amount, to) {
  storage.balances.add(ValueNote::new(amount, to)
  ctx.enqueue_public_call(_deduct(amount, ctx.msg_sender())
}

public internal fn _deduct(amount, from) {
  storage.public_balances.at(from) -= amount
}

```

but that isn’t currently in the example contract because it is less flexible.

---

<div class="post-metadata">

**Author:** ![oleh](https://dub1.discourse-cdn.com/flex013/user_avatar/forum.aztec.network/oleh/32/919_2.png) [@oleh](https://forum.aztec.network/u/oleh)\
**Post date:** [September 9, 2024, 9:01pm UTC](https://forum.aztec.network/t/rfc-simplifying-token-transfer-mechanisms-by-removing-shielding/6101/3 "2024-09-09T21:01:00Z")

</div>

Can’t you do something like this:

```rs
let to_keys = get_current_public_keys(to);
let note = TokenNote::new(amount, to_keys.npk_m.hash());
storage.balances.insert_from_public(note);

```

?

---

<div class="post-metadata">

**Author:** ![joshc](https://dub1.discourse-cdn.com/flex013/user_avatar/forum.aztec.network/joshc/32/20_2.png) [@joshc](https://forum.aztec.network/u/joshc)\
**Post date:** [September 10, 2024, 4:52pm UTC](https://forum.aztec.network/t/rfc-simplifying-token-transfer-mechanisms-by-removing-shielding/6101/4 "2024-09-10T16:52:31Z")

</div>

Yea I believe that would work. Just being mindful that the `transfer_from_public_to_private` function would reveal information about who the tokens are being transferred to, whereas the `shield` function hides this information. As previously mentioned, it is also less flexible. Other contracts could `redeem_shield` using the `secret`, but this wouldn’t work for `transfer_from_public_to_private`.

This might be a desirable trade-off for legibility and simplicity.

---

<div class="post-metadata">

**Author:** ![benesjan](https://dub1.discourse-cdn.com/flex013/user_avatar/forum.aztec.network/benesjan/32/39_2.png) [@benesjan](https://forum.aztec.network/u/benesjan)\
**Post date:** [September 19, 2024, 10:53am UTC](https://forum.aztec.network/t/rfc-simplifying-token-transfer-mechanisms-by-removing-shielding/6101/5 "2024-09-19T10:53:58Z")

</div>

Phasing out the shield terminology is definitely a good idea and we decided to go in that direction in our [NFT contract](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/noir-contracts/contracts/nft_contract/src/main.nr). We plan on following the same flows in the fungible tokens as well. We just didn’t get to it yet because there are a few things we want to tackle before doing that.

Thanks for the post 😊
