Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: remove asset from create note #686

Merged
merged 4 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* [BREAKING] Updated `create_swap_note()` procedure to return `NoteDetails` and defined SWAP note tag format (#665).
* [BREAKING] Added support for full details of private notes, renamed `OutputNote` variants and changed their meaning (#673).
* Implemented `OutputNoteBuilder` (#669).
* [BREAKING] Removed assets from `create_note` procedure and added new procedure `add_asset_to_note` (#686, #674).

## 0.2.3 (2024-04-26) - `miden-tx` crate only

Expand Down
52 changes: 30 additions & 22 deletions docs/architecture/accounts.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,33 +106,41 @@ There is also a standard for a [basic fungible faucet](https://github.com/0xPoly
#!
#! ...
export.distribute
# get max supply of this faucet. We assume it is stored at pos 3 of slot 1
push.METADATA_SLOT exec.account::get_item drop drop drop
# => [max_supply, amount, tag, note_type, RECIPIENT, ...]
# get max supply of this faucet. We assume it is stored at pos 3 of slot 1
push.METADATA_SLOT exec.account::get_item drop drop drop
# => [max_supply, amount, tag, note_type, RECIPIENT, ...]
# get total issuance of this faucet so far and add amount to be minted
exec.faucet::get_total_issuance
# => [total_issuance, max_supply, amount, tag, note_type RECIPIENT, ...]
# get total issuance of this faucet so far and add amount to be minted
exec.faucet::get_total_issuance
# => [total_issuance, max_supply, amount, tag, note_type RECIPIENT, ...]
# compute maximum amount that can be minted, max_mint_amount = max_supply - total_issuance
sub
# => [max_supply - total_issuance, amount, tag, note_type, RECIPIENT, ...]
# compute maximum amount that can be minted, max_mint_amount = max_supply - total_issuance
sub
# => [max_supply - total_issuance, amount, tag, note_type, RECIPIENT, ...]
# check that amount =< max_supply - total_issuance, fails if otherwise
dup.1 gte assert.err=ERR_BASIC_FUNGIBLE_MAX_SUPPLY_OVERFLOW
# => [asset, tag, note_type, RECIPIENT, ...]
# check that amount =< max_supply - total_issuance, fails if otherwise
dup.1 gte assert.err=ERR_BASIC_FUNGIBLE_MAX_SUPPLY_OVERFLOW
# => [asset, tag, note_type, RECIPIENT, ...]
# creating the asset
exec.asset::create_fungible_asset
# => [ASSET, tag, note_type, RECIPIENT, ...]
# creating the asset
exec.asset::create_fungible_asset
# => [ASSET, tag, note_type, RECIPIENT, ...]
# mint the asset; this is needed to satisfy asset preservation logic.
exec.faucet::mint
# => [ASSET, tag, note_type, RECIPIENT, ...]
# mint the asset; this is needed to satisfy asset preservation logic.
exec.faucet::mint
# => [ASSET, tag, note_type, RECIPIENT, ...]
# create a note containing the asset
exec.tx::create_note
# => [note_ptr, ZERO, ZERO, ...]
# store and drop the ASSET
mem_storew.3 dropw
# => [tag, note_type, RECIPIENT, ...]
# create a note containing the asset
exec.tx::create_note
# => [note_ptr, ZERO, ZERO, ...]
# store and drop the ASSET
padw mem_loadw.3 movup.4 exec.tx::add_asset_to_note
# => [note_ptr, ASSET, ZERO, ...]
end
#! Burns fungible assets.
Expand All @@ -153,7 +161,7 @@ There is also a standard for a [basic fungible faucet](https://github.com/0xPoly
```
</details>

The contract exposes two functions `distribute` and `burn`.
The contract exposes two functions `distribute` and `burn`.

The first function `distribute` can only be called by the faucet owner, otherwise it fails. As inputs, the function expects everything that is needed to create a note containing the freshly minted asset, i.e., amount, metadata, and recipient.

Expand Down
19 changes: 13 additions & 6 deletions miden-lib/asm/kernels/transaction/api.masm
Original file line number Diff line number Diff line change
Expand Up @@ -514,21 +514,28 @@ end

#! Creates a new note and returns a pointer to the memory address at which the note is stored.
#!
#! Inputs: [ASSET, tag, note_type, RECIPIENT]
#! Outputs: [ptr, 0, 0, 0, 0, 0, 0, 0, 0, 0]
#! Inputs: [tag, note_type, RECIPIENT]
#! Outputs: [note_ptr, 0, 0, 0, 0, 0]
#!
#! ASSET is the asset to be included in the note.
#! tag is the tag to be included in the note.
#! note_type is the note storage type
#! RECIPIENT is the recipient of the note.
#! ptr is the pointer to the memory address at which the note is stored.
#! note_ptr is the pointer to the memory address at which the note is stored.
export.create_note
# authenticate that the procedure invocation originates from the account context
exec.authenticate_account_origin
# => [ASSET, tag, note_type, RECIPIENT]
# => [tag, note_type, RECIPIENT]

exec.tx::create_note
# => [ptr, 0, 0, 0, 0, 0, 0, 0, 0, 0]
# => [note_ptr]

# prepare stack for return. Note: when create_note is called, the stack looks
# like [tag, note_type, RECIPIENT, x, x, X], with 16 elements and X might be important data
# for the user. Without padding the kernel returns [note_ptr, x, x, X, 0, ZERO] adding 0's.
# To keep the data in position we insert 0's between ptr and the potentially important
# first element x.
movupw.3 movup.15 movup.5
# => [note_ptr, 0, 0, 0, 0, 0]
Comment on lines +532 to +538
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we update the output stack as suggested in the previous comment, I don't think we'll need this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For all other procedures in this file, we do this kind of padding and return the stack as is in the subsequent procedures.

Should we discuss in the issue?

end

#! Adds an ASSET to the specified note and returns a pointer to the memory address
Expand Down
12 changes: 10 additions & 2 deletions miden-lib/asm/miden/contracts/faucets/basic_fungible.masm
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export.basic::auth_tx_rpo_falcon512
#! FAILS if:
#! - The transaction is being executed against an account that is not a fungible asset faucet.
#! - The total issuance after minting is greater than the maximum allowed supply.
export.distribute
export.distribute.1
# get max supply of this faucet. We assume it is stored at pos 3 of slot 1
push.METADATA_SLOT exec.account::get_item drop drop drop
# => [max_supply, amount, tag, note_type, RECIPIENT, ...]
Expand All @@ -72,9 +72,17 @@ export.distribute
exec.faucet::mint
# => [ASSET, tag, note_type, RECIPIENT, ...]

# store and drop the ASSET
loc_storew.0 dropw
# => [tag, note_type, RECIPIENT, ...]

# create a note containing the asset
exec.tx::create_note
# => [note_ptr, ZERO, ZERO, ...]

# store and drop the ASSET
padw loc_loadw.0 movup.4 exec.tx::add_asset_to_note
# => [note_ptr, ASSET, ZERO, ...]
end

#! Burns fungible assets.
Expand All @@ -99,4 +107,4 @@ export.burn
# clear the stack
padw swapw dropw
# => [...]
end
end
21 changes: 17 additions & 4 deletions miden-lib/asm/miden/contracts/wallets/basic.masm
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,14 @@ end
#! - The fungible asset is not found in the vault.
#! - The amount of the fungible asset in the vault is less than the amount to be removed.
#! - The non-fungible asset is not found in the vault.
export.send_asset
export.send_asset.1
exec.account::remove_asset
# => [ASSET, tag, note_type, RECIPIENT, ...]

# Store the ASSET for later
loc_storew.0 dropw
# => [tag, note_type, RECIPIENT, ...]

# This procedure is written to be executed with `exec` or `call`. When this
# procedure is `call`ed the stack has to be carefully manipulated to avoid
# inserting unwanted elements between the user data. The convention is to
Expand All @@ -53,9 +57,18 @@ export.send_asset
# is because the VM stack has a minimum size of 16 elements, trying to push
# elements after the call to `create_note` would increase the stack in
# addition to the minimum 16 elements.
push.0.0 padw movdnw.3 padw movdnw.3 movdn.11 drop
# => [ASSET, tag, note_type, RECIPIENT, ZERO, ZERO, 0, ...]
push.0 movdn.6 push.0 movdn.6 padw movdnw.2 padw movdnw.2
# => [tag, note_type, RECIPIENT, 0, 0, ZERO, ZERO, ...]

exec.tx::create_note
# => [note_ptr, ZERO, ZERO, 0, ...]
# => [note_ptr, 0, ZERO, ZERO, ...]

padw loc_loadw.0 movup.4
# => [note_ptr, ASSET, 0, ZERO, ZERO, ...]

exec.tx::add_asset_to_note
# => [note_ptr, 0, ZERO, ZERO, ...]

# prepare the stack for return - stack has 5 elements too many
movupw.3 dropw swap drop
Comment on lines +72 to +73
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to do this now while previously we didn't have to?

Separately, I wonder if a better approach here would be to call sys::truncate_stack. It would be a bit more expensive - but also generic in a way we won't need to worry about how many elements on the staack are extra. This could be done as a part of #685.

end
67 changes: 26 additions & 41 deletions miden-lib/asm/miden/kernels/tx/tx.masm
Original file line number Diff line number Diff line change
Expand Up @@ -243,87 +243,72 @@ end

#! Creates a new note and returns a pointer to the memory address at which the note is stored.
#!
#! Inputs: [ASSET, tag, note_type, RECIPIENT]
#! Outputs: [note_ptr, 0, 0, 0, 0, 0, 0, 0, 0]
#! Inputs: [tag, note_type, RECIPIENT]
#! Outputs: [note_ptr]
#!
#! ASSET is the asset to be included in the note.
#! tag is the tag to be included in the note.
#! RECIPIENT is the recipient of the note.
#! ptr is the pointer to the memory address at which the note is stored.
#! note_ptr is the pointer to the memory address at which the note is stored.
#!
#! Panics if
#! - the note_type is not valid
#! - the note_tag is not an u32
export.create_note
# validate the asset
exec.asset::validate_asset
# => [ASSET, tag, note_type, RECIPIENT]

# validate the note type
# NOTE: encrypted notes are currently unsupported `dup.6 push.ENCRYPTED_NOTE eq or`
dup.5 push.OFFCHAIN_NOTE eq dup.6 push.PUBLIC_NOTE eq or assert.err=ERR_INVALID_NOTE_TYPE
# => [ASSET, tag, note_type, RECIPIENT]
# NOTE: encrypted notes are currently unsupported
dup.1 push.OFFCHAIN_NOTE eq dup.2 push.PUBLIC_NOTE eq or assert.err=ERR_INVALID_NOTE_TYPE
# => [tag, note_type, RECIPIENT]

# copy data to validate the tag
dup.5 push.PUBLIC_NOTE dup.1 dup.7
# => [tag, note_type, public_note, note_type, ASSET, tag, note_type, RECIPIENT]
dup.1 push.PUBLIC_NOTE dup.1 dup.3
# => [tag, note_type, public_note, note_type, tag, note_type, RECIPIENT]

u32assert.err=ERR_NOTE_TAG_MUST_BE_U32
# => [tag, note_type, public_note, note_type, ASSET, tag, note_type, RECIPIENT]
# => [tag, note_type, public_note, note_type, tag, note_type, RECIPIENT]

# enforce the note type depending on the tag's bits
u32shr.30 push.ALL_NOTE_TYPES_ALLOWED eq cdrop assert_eq.err=ERR_NOTE_INVALID_TYPE_FOR_TAG
# => [ASSET, tag, note_type, RECIPIENT]
# => [tag, note_type, RECIPIENT]

# get the index for the next note to be created and increment counter
exec.increment_num_created_notes
# => [note_idx, ASSET, tag, note_type, RECIPIENT]
# => [note_idx, tag, note_type, RECIPIENT]

# get a pointer to the memory address at which the note will be stored
exec.memory::get_created_note_ptr
# => [note_ptr, ASSET, tag, note_type, RECIPIENT]
# => [note_ptr, tag, note_type, RECIPIENT]

# populate the metadata
movup.5 exec.account::get_id movup.7
# => [note_type, sender_acct_id, tag, note_ptr, ASSET, RECIPIENT]
swap exec.account::get_id movup.3
# => [note_type, sender_acct_id, tag, note_ptr, RECIPIENT]

push.0 # TODO: allow the user to push the aux data
# => [aux, note_type, sender_acct_id, tag, note_ptr, ASSET, RECIPIENT]
# => [aux, note_type, sender_acct_id, tag, note_ptr, RECIPIENT]

emit.NEW_NOTE_EVENT

# set the metadata for the new created note
dup.4 exec.memory::set_created_note_metadata
# => [note_ptr, ASSET, RECIPIENT]

# set the number of assets for the note to 1
push.1 dup.1 exec.memory::set_created_note_num_assets
# => [note_ptr, ASSET, RECIPIENT]

movdn.4 padw swapw movup.8
# => [note_ptr, ASSET, 0, 0, 0, 0, RECIPIENT]

# add the asset to the note
dup movdn.5 exec.memory::get_created_note_asset_data_ptr mem_storew dropw
# => [note_ptr, 0, 0, 0, 0, RECIPIENT]

movdn.8 swapw padw swapw movup.12
# => [note_ptr, RECIPIENT, 0, 0, 0, 0, 0, 0, 0, 0]
# => [note_ptr, RECIPIENT]

# set the recipient
dup movdn.5 exec.memory::set_created_note_recipient
# => [note_ptr, 0, 0, 0, 0, 0, 0, 0, 0]
# => [note_ptr]
end

#! Adds an ASSET to the specified note and returns a pointer to the memory address
#! at which the note is stored.
#!
#! Panics if
#! - the ASSET is malformed (invalid faucet ID)
#! - the max amount of fungible assets is exceeded
#! - the non-fungible asset already exists in the note
#!
#! Inputs: [note_ptr, ASSET]
#! Outputs: [note_ptr]
#!
#! note_ptr is the pointer to the memory address at which the note is stored.
#! ASSET can be a fungible or non-fungible asset.
#!
#! Panics if
#! - the ASSET is malformed (invalid faucet ID)
#! - the max amount of fungible assets is exceeded
#! - the non-fungible asset already exists in the note
export.add_asset_to_note
# get current num of assets
dup exec.memory::get_created_note_num_assets movdn.5
Expand Down
7 changes: 3 additions & 4 deletions miden-lib/asm/miden/tx.masm
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,19 @@ end

#! Creates a new note and returns a pointer to the memory address at which the note is stored.
#!
#! Inputs: [ASSET, tag, note_type, RECIPIENT]
#! Inputs: [tag, note_type, RECIPIENT]
#! Outputs: [note_ptr]
#!
#! ASSET is the asset to be included in the note.
#! tag is the tag to be included in the note.
#! note_type is the storage type of the note
#! RECIPIENT is the recipient of the note.
#! note_ptr is the pointer to the memory address at which the note is stored.
export.create_note
syscall.create_note
# => [note_ptr, ZERO, ZERO, 0]
# => [note_ptr, ZERO, 0]

# clear the padding from the kernel response
movdn.8 dropw dropw swap drop
movdn.4 dropw swap drop
# => [note_ptr]
end

Expand Down
Loading
Loading