0xPolygonMiden / miden-client

Client library that facilitates interaction with the Miden rollup
MIT License
32 stars 27 forks source link

Add ability to inject custom transactions to the Miden client #203

Closed Dominik1999 closed 5 months ago

Dominik1999 commented 6 months ago

+++ Updated issue text to summarize the discussion +++

Users will need more flexibility in executing transactions

Currently, we limit the way users can transact in Miden. For example, we only allow users to create notes with standardized scripts (P2ID, P2IDR, SWAP). Secondly, users cannot simply call a smart contract without using a note in the current client implementation.

We want users to be able to customize their transactions, code their note and transaction scripts, and create custom notes using the Miden client. We also want users to be able to consume notes with their NoteArgs that the executing account can inject at note consumption. This will widen the space for use cases, as users can define their logic when consuming notes.

The Rust side of things

Putting the serialization aspect of this aside, we want some TransactionRequest object, which in Rust could look something like this:

pub struct TransactionRequest {
    /// ID of the account against which the transactions is to be executed.
    account_id: AccountId,
    /// Notes to be consumed by the transaction together with their arguments.
    input_notes: BTreeMap<NodeId, (Note, NoteArgs)>,
    /// A list of notes expected to be generated by the transactions.
    expected_output_notes: Vec<Note>,
    /// Optional transaction script (together with its arguments).
    tx_script: Option<TransactionScript>
}

(this is not fully fledged out yet)

One tricky thing about the above is the type of expected_output_notes. Specifically, for some notes, we may know full note details, while for others, we may know only recipient + assets. But this is a general problem we have in other places too, and hopefully, we'll find a way to solve it at the level of miden-base.

Assuming the above is solved, we may be able to change the signature of the Client::new_transaction() method to something like this:

pub fn new_transaction(
    &mut self,
    tx_request: TransactionRequest,
) -> Result<TransactionResult, ClientError>

Injecting custom transactions into the client

A user must be able to inject this TransactionRequest into the Miden client for execution. We need a new CLI subcommand and a way to read the data.

Another open question is how users can create the TransactionRequest. But we can keep this for the discussion.

This question can also be discussed with our Pioneers. @gubloon They might need this feature at first. In theory, they can also create valid TransactionRequests in Typescript. We could add such functionality to the Playground.

bobbinth commented 6 months ago

As a user, I want to create notes with custom scripts using the Miden client. I want to use a CLI command like

miden-client tx new custom <PATH_TO_DIRECTORY/FILE_NAME>

Whereas in the CLI expects in two files, one *.masm and one *.inputs.

This seems to be more about allowing custom tx scripts rather than custom note scripts (i.e., the file at the specified path would contain a tx script, not a note script, right?).

In general, users do not create notes directly. The notes are created only when executing transactions - so, the general approach described here is correct. That is, we want to execute a custom transaction which may create custom notes. To execute a transaction though, we need to know much more than its tx script. Specifically, we also need to know which account it is going to be executed against, any notes we are planning to consume, and maybe something else. So, I wonder if instead of passing all this info via a command line, we should define a transaction file which can be executed via tx new custom command.

One other use case for such file could be for an order-book DEX. In such situations, an order-book DEX would create a transaction for the user, and then the user will just execute this transaction via CLI (or another client).

Separately, it might be good to add some kind of user confirmation to transaction execution flow. Specifically, after transaction is executed, but before it is submitted to the network, we should show to the user the effect this transaction would have on the account (e.g., it would add x tokens to the account, or remove y tokens etc.).

Dominik1999 commented 6 months ago

This seems to be more about allowing custom tx scripts rather than custom note scripts (i.e., the file at the specified path would contain a tx script, not a note script, right?).

I was actually thinking more of a note script (not a transaction script). As you said, we can create notes by executing a transaction that creates a specified note with the user-defined script.

I like the idea of the transaction file. It could looks like

[account]
account_id: 

[input_notes]
{}
(here we also could specify note_args)

[output_notes]
{0: 
    asset: 
    tag:
    recipient:
    serial_number:
    inputs: 
    note_script: `./<PATH-TO-FILE>`;

1:
    ...
}

[tx_script]
"
begin
    authenticate
end
"
bobbinth commented 6 months ago

Putting serialization aspect of this aside, I think we want some kind of TransactionRequest object which in Rust could look something like this:

pub struct TransactionRequest {
    /// ID of the account against which the transactions is to be executed.
    account_id: AccountId,
    /// Notes to be consumed by the transaction together with their arguments.
    input_notes: BTreeMap<NodeId, NoteArgs>,
    /// A list of notes expected to be generated by the transactions.
    expected_output_notes: Vec<Note>,
    /// Optional transaction script (together with its arguments).
    tx_script: Option<TransactionScript>
}

One tricky thing about the above is the type of expected_output_notes. Specifically, for some notes, we may know full note details, while for others, we may know only recipient + assets. But this is a general problem we have in other places too, and hopefully, we'll find a way to solve it at the level of miden-base.

Assuming the above is solved, we may be able to change the signature of the Client::new_transaction() method to something like this:

pub fn new_transaction(
    &mut self,
    tx_request: TransactionRequest,
) -> Result<TransactionResult, ClientError>
igamigo commented 5 months ago

Closed by #237