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

Add ARC-30: adding self.parent opcode #9

Merged
merged 1 commit into from
Sep 20, 2022
Merged
Changes from all 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
192 changes: 192 additions & 0 deletions arc-0030/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
---
arc: 0030 # Add the next sequence number
title: Adding self.parent opcode # Title
authors: [email protected] [email protected] # Add all Github usernames, emails, and/or full names
discussion: ARC-0030: Adding self.parent opcode # Create a 'Github Discussion' titled 'ARC-XXXX: {TITLE}`
topic: Application # Choose: Protocol, Network, or Application
status: Draft
created: 9/2/2022 # Date
---

## Abstract

Let's get NFTs & Tokens/DeFI working on Aleo. Currently, you can create an ERC-20/ERC-721-like program on Aleo but it is severly limited.
The biggest limitation is that a program cannot own an NFT. This prevents these Aleo tokens from being used in: escrow, auctions, pools, etc.

In order to enable this functionality, we need an opcode in the Aleo instruction set like: `self.parent`. This opcode would be similar to `self.caller` except it would result in the address of the program who called another program.

By creating this opcode, we could design token/nft programs to enable ownership through a public mapping, enabling Aleo users to transfer assets to a program. A program could then hold them in escrow and only release them as dictated through the smart contract.

In ethereum, there's a concept of `tx.origin` -> `self.caller` and `msg.sender`. Currently, there's no `msg.sender` equivalent in ethereum.

<!-- What problem does this proposal address? -->

<!-- If someone only reads this far, what do you want them to know? -->


## Specification

Given two programs: token.aleo & escrow.aleo

```
program token.aleo;

mapping balances:
owner as address.public;
amount as u64.public;

function transfer:
input r0 as address.private;
input r1 as u64.private;

finalize self.caller r0 r1;

finalize transfer:
input r0 as address.public;
input r1 as address.public;
input r2 as u64.public;

decrement balances[r0] by r2;
increment balances[r1] by r2;

function transfer_program:
input r0 as address.private;
input r1 as u64.private;

finalize self.parent r0 r1;

finalize transfer_program:
input r0 as address.public;
input r1 as address.public;
input r2 as u64.public;

decrement balances[r0] by r2;
increment balances[r1] by r2;

function get_balance:
input r0 as address.private;

cast balances[r0] into r1 as u64;

output r1 as u64;
```

```
import token_one.aleo; // can be copy-pasted from token.aleo
import token_two.aleo; // can be copy-pasted from token.aleo

program amm.aleo;

mapping shares:
owner as address.public;
amount as u64.public;

function deposit_token_two:
input r0 as u64.private;

call token_two.aleo/transfer swap.aleo r0; // Deposit into pool
call token_two.aleo/get_balance swap.aleo into r1; // Get balance of pool

mul r0 4294967296u64 into r2; // Multiply deposit by 2^32 to prevent underflow
div r2 r1 into r3; // Divide deposit by total pool

finalize self.caller r0;

finalize deposit_token_two:
input r0 as address.public;
input r1 as u64.public;

increment shares[r0] by r1; // keep track of individual shares
increment shares[swap.aleo] by r1; // keep track of total shares

function withdraw_token_two:
input r0 as u64.private; // Shares to withdraw
call token_two.aleo/get_balance swap.aleo into r1; // Get balance of pool
cast shares[swap.aleo] into r2 as u64; // Total shares in the pool

// Get to transfer: shares * pool_balance / total_shares
mul r0 r1 into r3;
div r3 r2 into r4;

call token_two.aleo/transfer_program self.caller r4;

finalize self.caller r1;

finalize withdrawl_token_two:
input r0 as address.public;
input r1 as u64.public;

decrement shares[r0] by r1; // keep track of individual shares
decrement shares[swap.aleo] by r1; // keep track of total shares

function convert_token_one_to_token_two:
input r0 as u64.private;

mul r0 2u64 into r1; // Mocking a price of 1 token_one = 2 token_two
sub r1 1u64 into r2; // Charge some fee for conversion

call token_one.aleo/transfer swap.aleo r0;
call token_two.aleo/transfer_program self.caller r2;

finalize self.parent r0 r1;
```

<!-- Define key terminology here. -->
`self.parent` should default to the address of the calling program if there is one. If there isn't a calling program, it should result in the same address as `self.caller`.

<!-- Describe the architecture. -->
In our AMM example, we define toy token and amm programs to demonstrate how `self.parent` would be used to enable a program to own assets. In `token.aleo`, a user can transfer assets to a program (`amm.aleo`) by calling `transfer` and assets can be transferred out of the pool by calling `transfer_program`. Effectively, `self.parent` gives `amm.aleo` exclusive control to decide how its balance in `token.aleo` is decremented. In our case, we show how a toy AMM could enable pool deposits/lp share issuance, lp share redemption, and swaps.

<!-- Include process diagrams. -->

### Test Cases

```
program bar.aleo;

function get_bar:
output self.parent as address.public;
```

```
program foo.aleo;


function get_foo:
call bar.aleo/get_address into r0;

output r0 as address.public;
```

`aleo run get_foo` -> `address(foo.aleo)`
`aleo run get_bar` -> `address(self.caller)`



## Dependencies

<!-- Will this affect the Aleo PM, Aleo Explorer, or Aleo Studio? -->

<!-- Will this affect Aleo, Leo, snarkOS, snarkVM, or any other repositories? -->
This will impact snarkVM and everything that has snarkVM as a dependency.

### Backwards Compatibility

<!-- List all backwards incompatibilities and their severity. -->

<!-- How will the backwards incompatibilities be resolved? -->
As this is a new feature, no programs should be impacted by adding a new opcode.


## Security & Compliance

<!-- Outline any potential security concerns. -->

<!-- Does this proposal introduce regulatory risk? -->
There should be no regulatory concerns.


## References

<!-- List any links that would be helpful for context. -->
Explanation of [tx.origin vs msg.sender in etherem](https://ethereum.stackexchange.com/questions/1891/whats-the-difference-between-msg-sender-and-tx-origin)