-
Notifications
You must be signed in to change notification settings - Fork 254
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
Create new ARC20 spec #41
Open
vicsn
wants to merge
5
commits into
AleoNet:master
Choose a base branch
from
vicsn:arc20_approvals
base: master
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
Changes from all commits
Commits
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 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 @@ | ||
build_** |
This file contains 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,45 @@ | ||
--- | ||
arc: 20 | ||
title: Design for ARC20 | ||
authors: The Aleo Team <[email protected]> | ||
discussion: https://github.com/AleoHQ/ARCs/discussions/42 | ||
topic: Application | ||
status: Living | ||
created: 2023-10-31 | ||
--- | ||
|
||
*A big thank you to [Valentin Seehausen](https://github.com/Valentin-Seehausen), [Evan Marshall](https://github.com/evanmarshall), [FullTimeMike](https://github.com/fulltimemike) and authors of the previous two ARC20 specs [Ghostant-1017](https://github.com/ghostant-1017) and [EdVeralli](https://github.com/EdVeralli).* | ||
|
||
## Abstract | ||
|
||
This ARC introduces a design for minimal Fungible Tokens just like ERC20. It allows for transferring tokens and approving programs to transfer tokens on your behalf. | ||
|
||
Given that Aleo does not support interfaces or inheritance, this spec is not enforced by the compiler. However, we invite the community to adhere to these standards in an effort to enhance interoperability between programs. | ||
|
||
The previous two ARC20 standards were built on old versions of snarkVM. Now that functionality is stabilizing, we can integrate the community's learnings in a new standard. This minimal initial standard is written in Aleo instructions for simplicity and enhanced auditability. In the future there are many extensions which might be valuable to standardize: | ||
- ERC1155-like multi-token standard | ||
- minting functionality | ||
- multisig or admin functionality | ||
|
||
Notes: | ||
- One can approve for more than the existing balance, but spending approved funds from others is of course limited by their balance. | ||
- No metadata is added to the program spec, though deployed program names can suffice as globally unique identifiers. | ||
- An update to snarkVM should soon enable passing an aleo program id as program input to `snarkos developer execute` | ||
- Before committing, this should be audited against the `credits.aleo` program. | ||
|
||
## Specification | ||
|
||
[token.aleo](./token.aleo) | ||
|
||
## Testing | ||
|
||
You can test this program on a local devnet. First, set up the devnet. Development private keys and addresses are printed to the terminal. Because the devnet runs in tmux, You can scroll up using `ctrl+b+[`. Be quick because history is limited by default. | ||
|
||
``` | ||
git clone github.com/aleoHQ/snarkOS | ||
cd snarkOS | ||
git checkout ca3e84c48 | ||
./devnet.sh | ||
``` | ||
|
||
Then run the `test.sh` script from the folder in this ARC repository. |
This file contains 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,16 @@ | ||
import token.aleo; | ||
|
||
program spender_tester.aleo; | ||
|
||
function transfer_from_public: | ||
input r0 as address.public; // approver | ||
input r1 as address.public; // receiver | ||
input r2 as u64.public; | ||
|
||
call token.aleo/transfer_from_public r0 r1 r2 into r3; | ||
async transfer_from_public r3 into r4; | ||
output r4 as spender_tester.aleo/transfer_from_public.future; | ||
|
||
finalize transfer_from_public: | ||
input r0 as token.aleo/transfer_from_public.future; | ||
await r0; |
This file contains 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 @@ | ||
{ | ||
"program": "spender_tester.aleo", | ||
"version": "0.0.0", | ||
"description": "", | ||
"license": "MIT" | ||
} |
This file contains 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,60 @@ | ||
set -e | ||
|
||
# Read the approver private key from the user | ||
read -p "Enter the private key with positive public account balance: " approver_private_key | ||
# Read the approver addresss from the user | ||
read -p "Enter the associated address with positive public account balance: " approver_address | ||
|
||
# throwaway keys | ||
spender_tester_private_key="APrivateKey1zkpB6TurrGgShJ7dsJ21HniMTF5WQc2eRy7d5o5QyBZFMFf" | ||
spender_tester_address="aleo1ew25qvyvd33gk9w4m8ehyhjamsm74r7n3ze9npnpux0rntzajgpqcm26pz" | ||
|
||
|
||
mkdir -p build_token | ||
cp token.aleo build_token/main.aleo | ||
cp token_program.json build_token/program.json | ||
|
||
echo """ | ||
|
||
/* This is only used for testing the spec */ | ||
function mint_public: | ||
input r0 as address.public; | ||
input r1 as u64.public; | ||
async mint_public r0 r1 into r2; | ||
output r2 as token.aleo/mint_public.future; | ||
|
||
finalize mint_public: | ||
input r0 as address.public; | ||
input r1 as u64.public; | ||
get.or_use account[r0] 0u64 into r2; | ||
add r2 r1 into r3; | ||
set r3 into account[r0]; | ||
""" >> build_token/main.aleo | ||
|
||
mkdir -p build_spender_tester | ||
cp spender_tester.aleo build_spender_tester/main.aleo | ||
cp spender_tester_program.json build_spender_tester/program.json | ||
mkdir -p build_spender_tester/imports | ||
cp build_token/main.aleo build_spender_tester/imports/token.aleo | ||
|
||
# deploy | ||
snarkos developer deploy token.aleo --private-key ${approver_private_key} --query "http://localhost:3030" --path "build_token" --broadcast "http://localhost:3030/testnet3/transaction/broadcast" --priority-fee 0 | ||
|
||
snarkos developer deploy spender_tester.aleo --private-key ${approver_private_key} --query "http://localhost:3030" --path "build_spender_tester" --broadcast "http://localhost:3030/testnet3/transaction/broadcast" --priority-fee 0 | ||
|
||
echo letting deployments settle for a few seconds... | ||
sleep 10 | ||
|
||
# mint tokens | ||
snarkos developer execute token.aleo mint_public ${approver_address} 10u64 --private-key ${approver_private_key} --query "http://localhost:3030" --broadcast "http://localhost:3030/testnet3/transaction/broadcast" | ||
|
||
# Transfer to spender so they have enough to cover the fee | ||
snarkos developer execute credits.aleo transfer_public ${spender_tester_address} 100000u64 --private-key ${approver_private_key} --query "http://localhost:3030" --broadcast "http://localhost:3030/testnet3/transaction/broadcast" | ||
|
||
snarkos developer execute token.aleo approve_public ${spender_tester_address} 1u64 --private-key ${approver_private_key} --query "http://localhost:3030" --broadcast "http://localhost:3030/testnet3/transaction/broadcast" | ||
|
||
snarkos developer execute token.aleo transfer_from_public ${approver_address} ${spender_tester_address} 1u64 --private-key ${spender_tester_private_key} --query "http://localhost:3030" --broadcast "http://localhost:3030/testnet3/transaction/broadcast" | ||
|
||
snarkos developer execute token.aleo approve_public big_spender.aleo 1u64 --private-key ${approver_private_key} --query "http://localhost:3030" --broadcast "http://localhost:3030/testnet3/transaction/broadcast" | ||
|
||
snarkos developer execute token.aleo transfer_from_public big_spender.aleo ${spender_tester_address} 1u64 --private-key ${spender_tester_private_key} --query "http://localhost:3030" --broadcast "http://localhost:3030/testnet3/transaction/broadcast" |
This file contains 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,148 @@ | ||
program token.aleo; | ||
|
||
mapping account: | ||
key as address.public; | ||
value as u64.public; | ||
|
||
record token: | ||
owner as address.private; | ||
amount as u64.private; | ||
|
||
struct approval: | ||
approver as address; | ||
spender as address; | ||
|
||
mapping approvals: | ||
key as field.public; | ||
value as u64.public; | ||
|
||
function approve_public: | ||
input r0 as address.public; // spender | ||
input r1 as u64.public; // amount spender is allowed to withdraw from approver | ||
|
||
// hash approval | ||
cast self.caller r0 into r2 as approval; | ||
hash.bhp256 r2 into r3 as field; | ||
|
||
async approve_public r3 r1 into r4; | ||
output r4 as token.aleo/approve_public.future; | ||
|
||
finalize approve_public: | ||
input r0 as field.public; | ||
input r1 as u64.public; // increase in amount spender is allowed to withdraw from approver | ||
|
||
// if approvals for approval field exists, the approved amount is increased. | ||
// otherwise, the approved allowance is created. | ||
get.or_use approvals[r0] 0u64 into r2; | ||
add r1 r2 into r3; | ||
set r3 into approvals[r0]; | ||
|
||
function unapprove_public: | ||
input r0 as address.public; // spender | ||
input r1 as u64.public; // amount spender's allowance is decreasing by | ||
|
||
// hash approval | ||
cast self.caller r0 into r2 as approval; | ||
hash.bhp256 r2 into r3 as field; | ||
|
||
async unapprove_public r3 r1 into r4; | ||
output r4 as token.aleo/unapprove_public.future; | ||
|
||
finalize unapprove_public: | ||
input r0 as field.public; | ||
input r1 as u64.public; // decrease in amount spender is allowed to withdraw from approver | ||
|
||
get approvals[r0] into r2; | ||
sub r2 r1 into r3; | ||
set r3 into approvals[r0]; | ||
|
||
/* Transfer From */ | ||
|
||
function transfer_from_public: | ||
input r0 as address.public; // from the approver | ||
input r1 as address.public; // to the receiver | ||
input r2 as u64.public; // amount to transfer | ||
|
||
cast r0 self.caller into r3 as approval; | ||
hash.bhp256 r3 into r4 as field; // hash approval | ||
|
||
async transfer_from_public r4 r0 r1 r2 into r5; | ||
output r5 as token.aleo/transfer_from_public.future; | ||
|
||
finalize transfer_from_public: | ||
input r0 as field.public; // approval | ||
input r1 as address.public; // from the approver | ||
input r2 as address.public; // to the receiver | ||
input r3 as u64.public; // amount to transfer | ||
|
||
get approvals[r0] into r4; | ||
sub r4 r3 into r5; | ||
set r5 into approvals[r0]; | ||
get account[r1] into r6; | ||
sub r6 r3 into r7; | ||
set r7 into account[r1]; | ||
get.or_use account[r2] 0u64 into r8; | ||
add r8 r3 into r9; | ||
set r9 into account[r2]; | ||
|
||
function transfer_public: | ||
input r0 as address.public; | ||
input r1 as u64.public; | ||
async transfer_public self.caller r0 r1 into r2; | ||
output r2 as token.aleo/transfer_public.future; | ||
|
||
finalize transfer_public: | ||
input r0 as address.public; | ||
input r1 as address.public; | ||
input r2 as u64.public; | ||
get.or_use account[r0] 0u64 into r3; | ||
sub r3 r2 into r4; | ||
set r4 into account[r0]; | ||
get.or_use account[r1] 0u64 into r5; | ||
add r5 r2 into r6; | ||
set r6 into account[r1]; | ||
|
||
|
||
function transfer_private: | ||
input r0 as token.record; | ||
input r1 as address.private; | ||
input r2 as u64.private; | ||
sub r0.amount r2 into r3; | ||
cast r0.owner r3 into r4 as token.record; | ||
cast r1 r2 into r5 as token.record; | ||
output r4 as token.record; | ||
output r5 as token.record; | ||
|
||
|
||
function transfer_private_to_public: | ||
input r0 as token.record; | ||
input r1 as address.public; | ||
input r2 as u64.public; | ||
sub r0.amount r2 into r3; | ||
cast r0.owner r3 into r4 as token.record; | ||
async transfer_private_to_public r1 r2 into r5; | ||
output r4 as token.record; | ||
output r5 as token.aleo/transfer_private_to_public.future; | ||
|
||
finalize transfer_private_to_public: | ||
input r0 as address.public; | ||
input r1 as u64.public; | ||
get.or_use account[r0] 0u64 into r2; | ||
add r2 r1 into r3; | ||
set r3 into account[r0]; | ||
|
||
|
||
function transfer_public_to_private: | ||
input r0 as address.public; | ||
input r1 as u64.public; | ||
cast r0 r1 into r2 as token.record; | ||
async transfer_public_to_private self.caller r1 into r3; | ||
output r2 as token.record; | ||
output r3 as token.aleo/transfer_public_to_private.future; | ||
|
||
finalize transfer_public_to_private: | ||
input r0 as address.public; | ||
input r1 as u64.public; | ||
get.or_use account[r0] 0u64 into r2; | ||
sub r2 r1 into r3; | ||
set r3 into account[r0]; |
This file contains 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 @@ | ||
{ | ||
"program": "token.aleo", | ||
"version": "0.0.0", | ||
"description": "", | ||
"license": "MIT" | ||
} |
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍