This repository was archived by the owner on Oct 25, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 9
Token wallet doc #1272
Open
codeblooded1729
wants to merge
22
commits into
main
Choose a base branch
from
kapil/token_wallet_doc
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Token wallet doc #1272
Changes from 11 commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
a3fe53c
checkpoint
codeblooded1729 39ffbad
checkpoint
codeblooded1729 995c5a8
checkpoint
codeblooded1729 fd699aa
Merge remote-tracking branch 'origin/main' into kapil/token_wallet_doc
codeblooded1729 c592ee3
remove gitignore files
jdkanani 9639f0d
first draft
codeblooded1729 3fd1bfb
delete tapes
codeblooded1729 78a1552
fix typo
codeblooded1729 10dab3e
Minor changes
SteveThakur 74dbec5
only one kind of wallet
codeblooded1729 22aaa03
add token and wallet
codeblooded1729 81cb8a8
checkpoint
codeblooded1729 65df22f
CPC doc
codeblooded1729 72092d3
update CPC
codeblooded1729 a047c57
update typo
codeblooded1729 290844d
update high level overview
codeblooded1729 ade15ff
remove token and wallet programs for a while
codeblooded1729 97a279d
remove gitignore
codeblooded1729 405298c
update authors
codeblooded1729 c672257
remove image
codeblooded1729 287aeaf
remove wallet example
codeblooded1729 8d4a8a6
Merge branch 'main' into kapil/token_wallet_doc
codeblooded1729 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| book |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| [book] | ||
| authors = ["codeblooded1729"] | ||
| language = "en" | ||
| multilingual = false | ||
| src = "src" | ||
| title = "wallet-token-example" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| # Summary | ||
|
|
||
| - [High level overview](./high_level_overview.md) | ||
| - [token program](./token.md) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| # High level overview | ||
|
|
||
| Consider the following scenario. | ||
|
|
||
| Alice owns a USDC token in her wallet. She has to transfer the token to Bob, who has his own wallet. | ||
|
|
||
| A USDC token is represented as `StateObject` with the constraint owner being the USDC token program represented through `ProgramIdentifier`. The USDC token, along with the amount, also stores the details of its owner (in this case, Alice) and her wallet program. The USDC program would require approval from Alice's wallet program in order to transfer the economic ownership to Bob and his wallet program. | ||
|
|
||
| ```rust | ||
| let alice_wallet: ProgramIdentifier; | ||
| let bob_wallet: ProgramIdentifier; | ||
|
|
||
| let usdc_token_object_data = USDCTokenData{ | ||
| usdc_token_owner: ALICE_PUBLIC_KEY; | ||
| wallet_program: alice_wallet; | ||
| amount: 100; | ||
| } | ||
|
|
||
| let usdc_token_program: ProgramIdentifier; | ||
|
|
||
| let usdc_token_object = StateObject{ | ||
| address: address_of_object_in_state_tree, | ||
| constraint_owner: usdc_token_program | ||
| data: usdc_token_object_data.to_bytes(), | ||
| } | ||
| ``` | ||
|
|
||
| At a high level, the programs are responsible for the following: | ||
|
|
||
| - `usdc_token_program` : | ||
| - - request `alice_wallet` to "make a call" to function that approves the transfer of `usdc_token_object` to `bob_wallet`. | ||
| - - gets "output of call", that is, approval of the transfer | ||
| - "propose a change" of `usdc_token_object`'s owner and wallet to that of Bob | ||
| - `alice_wallet` | ||
| - - receives, from `usdc_token_program` "request to call" the function to approve transfer of `usdc_token_object `to `bob_wallet` | ||
| - the function execution shows ownership of `usdc_token_object` by proving knowledge of private key corresponding to public key of `usdc_token_object`, which is supplied by Alice to the program through private tape | ||
| - sends "output of call", that is the approval of transfer back to `usdc_token_program` | ||
|
|
||
| But what exactly would happen when we say "make a call", get or send "output of call" and "propose a change" occur? | ||
| In practice, these won't occur in the usual sense. "Make a call" or send "output of call" don't correspond to a program calling another program or sending a response to other program. "Propose a change" does not refer to sending it to some entity who is listening in. | ||
|
|
||
| What would actually happen is that these programs would demonstrate that they have actually followed a script together, complied with each other's requests, and sent and received the intended responses. Each of the programs continues the execution as if it had "made the call" with correct arguments, computed the correct "output of call", and sent the intended response and "proposed" the intended state change. | ||
| This entire script is stored in two parts. `CallTape` is the part where the "make a call" and "output of call" events are stored. `EventTape` is the part where all the proposed changes to final state are stored. | ||
|
|
||
| We briefly describe how these tapes are created. The idea is that the play is performed, and then the script is created. Each program has two types of execution, native and zkvm. In the native execution all the "make a call", sending and receiving of "output of call" and "proposal to state change" are emulated in the intended manner, and the `CallTape `and `EventTape `is generated. In the zkvm execution, the actual functions mentioned in the `CallTape ` are executed by corresponding program, and their output is shown to be the same as the ones mentioned in the `CallTape`.' | ||
|
|
||
| In this scenario, the `CallTape` would attest to following events | ||
|
|
||
| - `usdc_token_program` called `alice_wallet` to execute the `approve_transfer` function with arguments `(usdc_token_object, bob_wallet)` | ||
| - `alice_wallet` program approved the transfer, and returned the boolean value `true` | ||
| - `usdc_token_program` read the response `true`. | ||
|
|
||
| The `EventTape` would attest to the following events | ||
|
|
||
| - `usdc_token_program` read `usdc_token_object` from the global state (before seeking approval from wallet program) | ||
| - `usdc_token_program` proposed an update to `usdc_token_object` while updating owner's public key, and wallet to that of Bob (after getting approval from the wallet program) | ||
|
|
||
| A zkvm execution of both programs produces a proof of their execution. The proof, along with attestation to `CallTape`, confirms that the programs followed the script mentioned in `CallTape`, that is complied with each other's requests and computed the correct function with correct output. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| # Token program | ||
|
|
||
| ```rust | ||
|
|
||
|
|
||
| pub fn main() { | ||
| // signals initiation of program | ||
| // Null program in some sense, provides the arguments | ||
| // to the token program, which are supplied by Alice | ||
| if let Some(message_from_null_to_token) = call_receive() { | ||
| let CPCMessage { | ||
| caller_program: null_program, | ||
| callee_program: token_program, | ||
codeblooded1729 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| args: transfer_call_args, | ||
| ret: transfer_done, | ||
| } = message_from_null_to_token.0; | ||
|
|
||
| if null_program != ProgramIdentifier::default() { | ||
codeblooded1729 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| panic!("Caller is not the null program"); | ||
| }; | ||
|
|
||
| // arguments supplied by alice | ||
| // id: token_program | ||
| // token_object: USDC token owned by alice | ||
| // remitter: alice's wallet program | ||
| // remittee: bob's wallet program | ||
| // remittee_public_key: bob's public key | ||
| let MethodArgs::Transfer(id, token_object, alice_wallet, bob_wallet, bob_public_key) = | ||
| transfer_call_args; | ||
|
|
||
| // assert that token object is owned by the token program | ||
| assert_eq!(token_program, token_object.constraint_owner); | ||
|
|
||
| // token program calls its transfer function on args supplied by Alice | ||
| let success = transfer(id, token_object, alice_wallet, bob_wallet); | ||
|
|
||
| if success = transfer_done { | ||
| panic!("Transfer failed"); | ||
| } | ||
| } else { | ||
| panic!("No One called the program"); | ||
codeblooded1729 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
|
|
||
| pub fn transfer( | ||
| token_program: ProgramIdentifier, | ||
| token_object: StateObject, | ||
| remitter_wallet: ProgramIdentifier, | ||
| remittee_wallet: ProgramIdentifier, | ||
| remittee_public_key: PublicKey, | ||
| ) -> bool { | ||
| // set up the args for approve_transfer function to be called by wallet program | ||
| let approve_transfer_args = Wallet::MethodArgs::ApproveTransfer( | ||
| token_object, | ||
| remitter_wallet, | ||
| remittee_wallet, | ||
| remittee_public_key, | ||
| ); | ||
| let approve_transfer_return = wallet::MethodReturns::ApproveTransfer(true); | ||
|
|
||
| // the native function that is run by wallet program | ||
| // This would be executed during native execution | ||
| // and facilitate generation of calltape | ||
| let native_approve_transfer = Wallet::approve_transfer; | ||
|
|
||
| let wallet::MethodReturns::ApproveTransfer(success) = call_send( | ||
codeblooded1729 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| token_program, | ||
| remitter_wallet, | ||
| approve_transfer_args, | ||
| native_approve_transfer, | ||
| approve_transfer_return, | ||
| ); | ||
|
|
||
| if success == approve_transfer_return { | ||
| let new_token_object = StateObject { | ||
| data: TokenData { | ||
| owner: remittee_public_key, | ||
| wallet: remittee_wallet, | ||
| amount: token_object.data.amount, | ||
| }, | ||
| }; | ||
|
|
||
| event_emit(self_prog_id, Event::UpdatedStateObject(new_token_object)); | ||
| } | ||
| } | ||
|
|
||
| ``` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| # Wallet program | ||
|
|
||
| ```rust | ||
| pub fn main() { | ||
| if let Some(message_from_token_program) = call_receive() { | ||
| let CPCMessage { | ||
| token_program, | ||
| wallet_program, | ||
| approve_call_args, | ||
| approval, | ||
| } = message_from_token_program.0; | ||
|
|
||
| let MethodArgs::ApproveTransfer(token_object, alice_wallet, bob_wallet) = approve_call_args; | ||
|
|
||
| assert_eq!( | ||
| approval, | ||
| approve_transfer(token_object, alice_wallet, bob_wallet) | ||
| ) | ||
| } else { | ||
| panic!("Failed to receive message from token program") | ||
| } | ||
| } | ||
|
|
||
| pub fn approve_transfer( | ||
| token_object: StateObject, | ||
| remitter_wallet: ProgramIdentifier, | ||
| remittee_wallet: ProgramIdentifier, | ||
| ) -> bool { | ||
| let (mut public_tape, mut private_tape) = get_tapes(); | ||
| let private_key = PrivateKey::from(private_tape); | ||
| let token_object_data = token_object.data.into(); | ||
| let public_key = token_object_data.public_key; | ||
| private_key == poseidon2_hash(public_key) | ||
| } | ||
|
|
||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| #![no_main] | ||
| #![feature(restricted_std)] | ||
|
|
||
| mod core_logic; | ||
|
|
||
| use mozak_sdk::io::{get_tapes, Extractor}; | ||
|
|
||
| pub fn main() { | ||
|
|
||
| let Some(message_from_token_program) = call_receive(){ | ||
| let CPCMessage{ | ||
| token_program, | ||
| wallet_program, | ||
| approve_call_args, | ||
| approval, | ||
| } = message_from_token_program.0; | ||
|
|
||
| let MethodArgs::ApproveTransfer(token_object, remitter_wallet, remittee_wallet) = approve_call_args; | ||
| return approval == approve_transfer(token_object, remitter_wallet, remittee_wallet); | ||
| } | ||
| } | ||
|
|
||
| pub fn approve_transfer( | ||
| token_object: StateObject, | ||
| remitter_wallet: ProgramIdentifier, | ||
| remittee_wallet: ProgramIdentifier) -> bool { | ||
|
|
||
| let (mut public_tape, mut _private_tape) = get_tapes(); | ||
|
|
||
| let private_key = PrivateKey::from(_private_tape); | ||
| let token_object_data = token_object.data.into(); | ||
| let public_key = token_object_data.public_key; | ||
| assert_eq!(remitter_wallet, token_object_data.wallet); | ||
| return private_key == poseidon2_hash(public_key); | ||
| } | ||
|
|
||
| core_logic.approve_transfer(token_object, remitter_wallet, remittee_wallet); | ||
| } | ||
|
|
||
| // We define `main()` to be the program's entry point. | ||
| guest::entry!(main); |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.