This commit is contained in:
evan-schott 2023-10-19 11:55:59 -07:00
parent 1fbc16ce24
commit aa37895d91
14 changed files with 1621 additions and 5 deletions

10
Cargo.lock generated
View File

@ -823,6 +823,15 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "disassembler"
version = "0.1.0"
dependencies = [
"leo-ast",
"leo-span",
"snarkvm",
]
[[package]]
name = "doc-comment"
version = "0.3.3"
@ -1380,6 +1389,7 @@ dependencies = [
"serde",
"serde_json",
"smallvec",
"snarkvm",
]
[[package]]

View File

@ -41,7 +41,8 @@ members = [
"docs/grammar",
"errors",
"leo/package",
"tests/test-framework"
"tests/test-framework",
"utils/disassembler"
]
[workspace.dependencies.snarkvm]

View File

@ -18,6 +18,9 @@ license = "GPL-3.0"
edition = "2021"
rust-version = "1.69"
[dependencies.snarkvm]
workspace = true
[dependencies.leo-errors]
path = "../../errors"
version = "=1.10.0"

View File

@ -16,6 +16,7 @@
use leo_errors::Result;
use leo_span::{Span, Symbol};
use snarkvm::console::program::Identifier as IdentifierCore;
use crate::{simple_node_impl, Node, NodeID};
use serde::{
@ -28,6 +29,9 @@ use serde::{
Serialize,
Serializer,
};
use snarkvm::{
prelude::Network,
};
use std::{
collections::BTreeMap,
fmt,
@ -152,3 +156,11 @@ impl<'de> Deserialize<'de> for Identifier {
deserializer.deserialize_str(IdentifierVisitor)
}
}
impl<N: Network> From<IdentifierCore<N>> for Identifier {
fn from(id: IdentifierCore<N>) -> Self {
let id_str = id.to_string();
dbg!(id_str.clone());
let a = "Dummy";
Self { name: Symbol::intern(a), span: Default::default(), id: Default::default() }
}
}

View File

@ -18,6 +18,7 @@ use crate::Identifier;
use core::fmt;
use serde::{de, de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
use snarkvm::{console::program::ProgramID, prelude::Network};
use std::collections::BTreeMap;
/// An identifier for a program that is eventually deployed to the network.
@ -92,3 +93,9 @@ impl<'de> Deserialize<'de> for ProgramId {
deserializer.deserialize_str(ProgramIdVisitor)
}
}
impl<N: Network> From<ProgramID<N>> for ProgramId {
fn from(program: ProgramID<N>) -> Self {
Self { name: Identifier::from(*program.name()), network: Identifier::from(*program.network()) }
}
}

View File

@ -17,12 +17,20 @@
pub mod member;
pub use member::*;
use crate::{Identifier, Node, NodeID};
use crate::{Identifier, Mode, Node, NodeID, Type};
use leo_span::{Span, Symbol};
use serde::{Deserialize, Serialize};
use std::fmt;
use snarkvm::{
console::program::{RecordType, StructType},
prelude::{
EntryType::{Private, Public, Constant},
Network,
},
};
/// A struct type definition, e.g., `struct Foo { my_field: Bar }`.
/// In some languages these are called `struct`s.
///
@ -77,3 +85,51 @@ impl fmt::Display for Struct {
}
crate::simple_node_impl!(Struct);
// impl<N: Network> From<&StructType<N>> for Struct {
// fn from(input: &StructType<N>) -> Self {
// Self {
// identifier: Identifier::from(input.name()),
// members: input
// .members()
// .iter()
// .map(|(id, type_)| Member {
// mode: Mode::None,
// identifier: Identifier::from(id),
// type_: Type::from(type_),
// span: Default::default(),
// id: Default::default(),
// })
// .collect(),
// is_record: false,
// span: Default::default(),
// id: Default::default(),
// }
// }
// }
//
// impl<N: Network> From<&RecordType<N>> for Struct {
// fn from(input: &RecordType<N>) -> Self {
// Self {
// identifier: Identifier::from(input.name()),
// members: input
// .entries()
// .iter()
// .map(|(id, entry)| Member {
// mode: Mode::None,
// identifier: Identifier::from(id),
// type_: match entry {
// Public(t) => Type::from(t),
// Private(t) => Type::from(t),
// Constant(t) => Type::from(t),
// },
// span: Default::default(),
// id: Default::default(),
// })
// .collect(),
// is_record: true,
// span: Default::default(),
// id: Default::default(),
// }
// }
// }

View File

@ -21,7 +21,8 @@ pub use finalize_stub::*;
pub mod function_stub;
pub use function_stub::*;
use crate::{ConstDeclaration, Identifier, Mapping, ProgramId, Struct};
use crate::{ConstDeclaration, Mapping, ProgramId, Struct};
use leo_span::{Span, Symbol};
use serde::{Deserialize, Serialize};
use std::fmt;
@ -30,7 +31,7 @@ use std::fmt;
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct Stub {
/// A vector of imported programs.
pub imports: Vec<Identifier>,
pub imports: Vec<ProgramId>,
/// The stub id
pub stub_id: ProgramId,
/// A vector of const definitions.

View File

@ -14,10 +14,15 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{ArrayType, Identifier, IntegerType, MappingType, TupleType};
use crate::{ArrayType, common, Identifier, IntegerType, MappingType, TupleType};
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use snarkvm::prelude::{
Network,
PlaintextType,
PlaintextType::{Array, Literal, Struct},
};
use std::fmt;
/// Explicit type used for defining a variable or expression type

View File

@ -0,0 +1,34 @@
/*
namespace: Compile
expectation: Pass
*/
program test.aleo {
struct message {
sender: u8,
object: u8,
}
mapping balances: u8 => u8;
transition a(arg1: message) -> message {
return message {
sender: 1u8,
object: 1u8,
};
}
function b(arg1: message) -> message {
return message {
sender: 1u8,
object: 1u8,
};
}
function c(arg1: balances) -> balances {
return arg1;
}
transition d(arg1: balances) -> balances {
return arg1;
}
}

View File

@ -0,0 +1,17 @@
[package]
name = "disassembler"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies.snarkvm]
workspace = true
[dependencies.leo-ast]
path = "../../compiler/ast"
version = "=1.9.4"
[dependencies.leo-span]
path = "../../compiler/span"
version = "1.9.3"

View File

@ -0,0 +1,383 @@
// Copyright (C) 2019-2023 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use snarkvm::{
console::network::Testnet3,
prelude::{Itertools, Network, RegisterType, ValueType},
synthesizer::{
program::{CommandTrait, InstructionTrait, Program, ProgramCore},
Command,
Instruction,
},
};
use snarkvm::console::program::Identifier as IdentifierCore;
use leo_span::Symbol;
use std::{ops::Add, str::FromStr};
use leo_ast::{Identifier, ProgramId, Struct, Stub};
use leo_ast::Type::Identifier as IdentifierType;
type CurrentNetwork = Testnet3;
fn main() {
let a = Symbol::intern("aleo");
}
// fn old() {
// // let credits_aleo =
// // std::fs::read_to_string("/Users/evanschott/work/leo/utils/disassembler/src/tests/credits.aleo").unwrap();
// // println!("{}", code_gen(credits_aleo));
// let aleo_prog_1 = r"import credits.aleo;
//
// import battleship.aleo;
// import juice.aleo;
//
// program to_parse.aleo;
//
// function new_board_state:
// input r0 as u64.private;
// input r1 as address.private;
// cast self.caller 0u64 0u64 r0 self.caller r1 false into r2 as board_state.record;
// output r2 as board_state.record;
//
// closure add_up:
// input r0 as u8;
// input r1 as u8;
// add r0 r1 into r2;
// output r2 as u8;
//
// function transfer_public_to_private:
// input r0 as address.private;
// input r1 as u64.public;
// cast r0 r1 into r2 as credits.record;
// async transfer_public_to_private self.caller r1 into r3;
// output r2 as credits.record;
// output r3 as credits.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];
// ";
// let program = Program::<CurrentNetwork>::from_str(aleo_prog_1);
// match program {
// Ok(p) => {
// let disassembled = disassemble(p);
// println!("{}", disassembled)
// }
// Err(e) => {
// println!("{}", e);
// }
// }
// // println!("{}", disassemble(Program::<CurrentNetwork>::from_str(aleo_prog_1).unwrap()));
// }
// fn disassemble<N: Network, Instruction: InstructionTrait<N>, Command: CommandTrait<N>>(
// program: ProgramCore<N, Instruction, Command>,
// ) -> Stub {
// dbg!(program.records());
//
// let mut stub = Stub {
// imports: Vec::new(),
// stub_id: ProgramId::from(program.id()),
// consts: Vec::new(),
// structs: Vec::new(),
// mappings: Vec::new(),
// functions: Vec::new(),
// span: Default::default(),
// };
//
//
// let structs = program.structs().iter().map(|(id,s)| {
// (Identifier::from(id).name, Struct::from(s))
// }).collect_vec();
// let records = program.records().iter().map(|(id,s)| {
// dbg!(id.clone());
// dbg!(s);
// println!("{}", id.clone());
// let id_str = id.clone().to_string();
// let id_sym = Symbol::intern(&id_str);
// ((id_sym, Struct::from(s)))
// }).collect_vec();
//
//
// stub
//
// // Stub {
// // imports: program.imports().into_iter().map(|(id, import)| ProgramId::from(id)).collect(),
// // stub_id: ProgramId::from(program.id()),
// // consts: Vec::new(),
// // structs: [structs,records].concat(),
// // mappings: Vec::new(),
// // functions: Vec::new(), // TODO: Add functions AND closures
// // span: Default::default(),
// // }
// }
fn print_visibility<N: Network>(visibility: &ValueType<N>) -> String {
match visibility {
ValueType::Public(_) => "public ".to_string(),
_ => "".to_string(),
}
}
fn print_transition_input<N: Network>(input: &ValueType<N>, index: usize, len: usize) -> String {
format!("{}a{}: {}", print_visibility(input), index + 1, print_transition_value(input, index, len))
}
fn print_transition_value<N: Network>(value: &ValueType<N>, index: usize, len: usize) -> String {
let value_str = match value {
ValueType::Constant(val) => format!("{}", val.to_string().replace("boolean", "bool")),
ValueType::Public(val) => format!("{}", val.to_string().replace("boolean", "bool")),
ValueType::Private(val) => format!("{}", val.to_string().replace("boolean", "bool")),
ValueType::Record(id) => format!("{}", id.to_string()),
ValueType::ExternalRecord(loc) => format!("{}.aleo/{}", loc.name(), loc.resource().to_string()),
ValueType::Future(_) => panic!("Futures must be filtered out by this stage"),
};
let situational_comma = if index == len - 1 { "" } else { ", " };
format!("{}{}", value_str, situational_comma)
}
fn print_transition_output<N: Network>(output: &ValueType<N>, index: usize, len: usize) -> String {
let (left, right) = if len == 1 {
(" -> ", "")
} else if index == 0 {
(" -> (", "")
} else if index == len - 1 {
("", ")")
} else {
("", "")
};
format!("{}{}{}", left, print_transition_value(output, index, len), right)
}
fn print_function_output<N: Network>(output: &RegisterType<N>, index: usize, len: usize) -> String {
let (left, right) = if len == 1 {
(" -> ", "")
} else if index == 0 {
(" -> (", "")
} else if index == len - 1 {
("", ")")
} else {
("", "")
};
format!("{}{}{}", left, print_function_value(output, index, len), right)
}
fn print_function_input<N: Network>(input: &RegisterType<N>, index: usize, len: usize) -> String {
format!("a{}: {}", index + 1, print_function_value(input, index, len))
}
fn print_function_value<N: Network>(value: &RegisterType<N>, index: usize, len: usize) -> String {
let value_str = match value {
RegisterType::Plaintext(val) => format!("{}", val.to_string().replace("boolean", "bool")),
RegisterType::Record(val) => format!("{}", val.to_string()),
RegisterType::ExternalRecord(loc) => format!("{}.aleo/{}", loc.name(), loc.resource().to_string()),
RegisterType::Future(_) => panic!("Futures must be filtered out by this stage"),
};
let situational_comma = if index == len - 1 { "" } else { ", " };
format!("{}{}", value_str, situational_comma)
}
fn code_gen(input: String) -> String {
// Parse a new program.
let result = Program::<CurrentNetwork>::from_str(&input).unwrap();
let mut output = format!("stub {}.aleo {{", result.id().name());
// Write imports
output.push_str(
&result.imports().into_iter().map(|(name, _)| format!("\n import {};\n", name)).collect::<String>(),
);
// Write records
output.push_str(
&result
.records()
.into_iter()
.map(|(name, fields)| {
format!("\n record {} {{\n owner: address,\n", name).add(
&(fields
.entries()
.into_iter()
.map(|(id, entry_type)| {
if entry_type.plaintext_type().to_string() == "boolean" {
return format!(" {}: bool,\n", id);
} else {
format!(" {}: {},\n", id, entry_type.plaintext_type().to_string())
}
})
.collect::<String>()
+ " }\n")
.to_string(),
)
})
.collect::<String>(),
);
// Write transitions
output.push_str(
&result
.functions()
.into_iter()
.map(|(name, value)| {
let (inputs, outputs) = (value.inputs(), value.outputs().clone());
// Can assume that last output is a future if the function has associated finalize
let outputs_vec = if value.finalize_logic().is_some() {
outputs[..outputs.len() - 1].iter().collect_vec()
} else {
outputs.iter().collect_vec()
};
let len = outputs_vec.len();
format!("\n transition {}(", name).add(
&(inputs
.into_iter()
.enumerate()
.map(|(index, input)| print_transition_input(&input.value_type(), index, inputs.len()))
.collect::<String>()
+ ")")
.add(
&(outputs_vec
.into_iter()
.enumerate()
.map(|(index, output)| print_transition_output(&output.value_type(), index, len))
.collect::<String>()
+ ";\n")
.to_string(),
),
)
})
.collect::<String>(),
);
// Write functions
output.push_str(
&result
.closures()
.into_iter()
.map(|(name, value)| {
let (inputs, outputs) = (value.inputs(), value.outputs().clone());
let len = outputs.len();
format!("\n function {}(", name).add(
&(inputs
.into_iter()
.enumerate()
.map(|(index, input)| print_function_input(&input.register_type(), index, inputs.len()))
.collect::<String>()
+ ")")
.add(
&(outputs
.into_iter()
.enumerate()
.map(|(index, output)| print_function_output(&output.register_type(), index, len))
.collect::<String>()
+ ";\n")
.to_string(),
),
)
})
.collect::<String>(),
);
// Append final closing bracket
output.push_str("}\n");
output
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn code_gen_test() {
let aleo_prog_1 = r"import credits.aleo;
import battleship.aleo;
import juice.aleo;
program to_parse.aleo;
record board_state:
owner as address.private;
hits_and_misses as u64.private;
played_tiles as u64.private;
ships as u64.private;
player_1 as address.private;
player_2 as address.private;
game_started as boolean.private;
function new_board_state:
input r0 as u64.private;
input r1 as address.private;
cast self.caller 0u64 0u64 r0 self.caller r1 false into r2 as board_state.record;
output r2 as board_state.record;
closure add_up:
input r0 as u8;
input r1 as u8;
add r0 r1 into r2;
output r2 as u8;
function transfer_public_to_private:
input r0 as address.private;
input r1 as u64.public;
cast r0 r1 into r2 as credits.record;
async transfer_public_to_private self.caller r1 into r3;
output r2 as credits.record;
output r3 as credits.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];
";
let leo_stub_1: &str = r"stub to_parse.aleo {
import credits.aleo;
import battleship.aleo;
import juice.aleo;
record board_state {
owner: address,
hits_and_misses: u64,
played_tiles: u64,
ships: u64,
player_1: address,
player_2: address,
game_started: bool,
}
transition new_board_state(a1: u64, a2: address) -> board_state;
transition transfer_public_to_private(a1: address, public a2: u64) -> credits;
function add_up(a1: u8, a2: u8) -> u8;
}
";
let code_gen_1 = code_gen(aleo_prog_1.to_string());
assert_eq!(code_gen_1, leo_stub_1);
}
}

View File

@ -0,0 +1,845 @@
// Copyright (C) 2019-2023 Aleo Systems Inc.
// This file is part of the snarkVM library.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**********************************************************************************************************************/
program credits.aleo;
/**********************************************************************************************************************/
/// The `committee` mapping contains the active validator set and their corresponding stake.
mapping committee:
// The key represents the address of the validator.
key as address.public;
// The value represents the committee state of the validator.
value as committee_state.public;
// The `committee_state` struct tracks the total stake of the validator, and whether they are open to stakers.
struct committee_state:
// The amount of microcredits bonded to the validator, by the validator and its delegators.
microcredits as u64;
// The boolean flag indicating if the validator is open to stakers.
is_open as boolean;
/**********************************************************************************************************************/
// The `bonded` mapping represents the amount of microcredits that are currently bonded.
mapping bonded:
// The key represents the address of the staker, which includes the validators and their delegators.
key as address.public;
// The value represents the bond state.
value as bond_state.public;
// The `bond_state` struct tracks the amount of microcredits that are currently bonded to the specified validator.
struct bond_state:
// The address of the validator.
validator as address;
// The amount of microcredits that are currently bonded to the specified validator.
microcredits as u64;
/**********************************************************************************************************************/
// The `unbonding` mapping contains a set of stakers with their unbonding microcredits and unlock height.
mapping unbonding:
// The key represents the address of the staker, which includes the validators and their delegators.
key as address.public;
// The value represents the unbond state.
value as unbond_state.public;
// The `unbond_state` struct tracks the microcredits that are currently unbonding, along with the unlock height.
struct unbond_state:
// The amount of microcredits that are currently unbonding.
microcredits as u64;
// The block height at which the unbonding will be complete, and can be claimed.
height as u32;
/**********************************************************************************************************************/
// The `account` mapping is used to store credits publicly.
mapping account:
// The key represents the address of the owner.
key as address.public;
// The value represents the amount of public microcredits that belong to the specified owner.
value as u64.public;
/**********************************************************************************************************************/
// The `credits` record is used to store credits privately.
record credits:
// The address of the owner.
owner as address.private;
// The amount of private microcredits that belong to the specified owner.
microcredits as u64.private;
/**********************************************************************************************************************/
// This function allows any staker to bond their microcredits to a validator.
// The corresponding functions for 'bond_public' are 'unbond_public' and 'claim_unbond_public'.
function bond_public:
// Input the validator's address.
input r0 as address.public;
// Input the amount of microcredits to bond.
input r1 as u64.public;
// Determine if the amount is at least one credit.
gte r1 1_000_000u64 into r2;
// Enforce the amount is at least one credit.
assert.eq r2 true;
// Bond the specified amount of microcredits to the specified validator.
async bond_public self.caller r0 r1 into r3;
// Output the finalize future.
output r3 as credits.aleo/bond_public.future;
finalize bond_public:
// Input the staker's address.
input r0 as address.public;
// Input the validator's address.
input r1 as address.public;
// Input the amount of microcredits to bond.
input r2 as u64.public;
// Determine whether the caller is a validator.
is.eq r0 r1 into r3;
// If the caller is a validator, jump to the `bond_validator` logic.
branch.eq r3 true to bond_validator;
// If the caller is not a validator, jump to the `bond_delegator` logic.
branch.eq r3 false to bond_delegator;
/******* Bond Validator *******/
// Starts the `bond_validator` logic.
position bond_validator;
/* Committee */
// Construct the initial committee state.
// Note: We set the initial 'is_open' state to 'true'.
cast 0u64 true into r4 as committee_state;
// Retrieve the committee state of the specified validator.
get.or_use committee[r0] r4 into r5;
// Ensure that the validator is open to stakers.
assert.eq r5.is_open true;
// Increment the stake for the specified validator.
add r5.microcredits r2 into r6;
// Construct the updated committee state.
cast r6 r5.is_open into r7 as committee_state;
/* Bonded */
// Construct the initial bond state.
cast r1 0u64 into r8 as bond_state;
// Get the bond state for the caller, or default to the initial bond state.
get.or_use bonded[r0] r8 into r9;
// Enforce the validator matches in the bond state.
assert.eq r9.validator r1;
// Increment the microcredits in the bond state.
add r9.microcredits r2 into r10;
// Determine if the amount is at least one million credits.
gte r10 1_000_000_000_000u64 into r11;
// Enforce the amount is at least one million credits.
assert.eq r11 true;
// Construct the updated bond state.
cast r1 r10 into r12 as bond_state;
/* Account */
// Get the balance of the caller.
// If the account does not exist, this finalize scope will fail.
get account[r0] into r13;
// Decrement the balance of the caller.
sub r13 r2 into r14;
/* Writes */
// Update the committee state of the specified validator.
set r7 into committee[r0];
// Update the bond state for the caller.
set r12 into bonded[r0];
// Update the balance of the caller.
set r14 into account[r0];
// Ends the `bond_validator` logic.
branch.eq true true to end;
/******* Bond Delegator *******/
// Starts the `bond_delegator` logic.
position bond_delegator;
/* Committee */
// Check if the caller is a validator.
contains committee[r0] into r15;
// Enforce the caller is *not* a validator.
assert.eq r15 false;
// Get the stake for the specified validator.
// If the validator does not exist, this finalize scope will fail.
get committee[r1] into r16;
// Ensure that the validator is open to stakers.
assert.eq r16.is_open true;
// Increment the stake for the specified validator.
add r16.microcredits r2 into r17;
// Construct the updated committee state.
cast r17 r16.is_open into r18 as committee_state;
/* Bonded */
// Construct the initial bond state.
cast r1 0u64 into r19 as bond_state;
// Get the bond state for the caller, or default to the initial bond state.
get.or_use bonded[r0] r19 into r20;
// Enforce the validator matches in the bond state.
assert.eq r20.validator r1;
// Increment the microcredits in the bond state.
add r20.microcredits r2 into r21;
// Determine if the amount is at least 10 credits.
gte r21 10_000_000u64 into r22;
// Enforce the amount is at least 10 credits.
assert.eq r22 true;
// Construct the updated bond state.
cast r1 r21 into r23 as bond_state;
/* Account */
// Get the balance of the caller.
// If the account does not exist, this finalize scope will fail.
get account[r0] into r24;
// Decrement the balance of the caller.
sub r24 r2 into r25;
/* Writes */
// Update the committee state for the specified validator.
set r18 into committee[r1];
// Update the bond state for the caller.
set r23 into bonded[r0];
// Update the balance of the caller.
set r25 into account[r0];
// The terminus.
position end;
/**********************************************************************************************************************/
// This function allows any staker to unbond their microcredits from a validator.
// The corresponding functions for 'unbond_public' is 'claim_unbond_public'.
function unbond_public:
// Input the amount of microcredits to unbond.
input r0 as u64.public;
// Unbond the specified amount of microcredits to the caller.
async unbond_public self.caller r0 into r1;
// Output the finalize future.
output r1 as credits.aleo/unbond_public.future;
finalize unbond_public:
// Input the staker's address.
input r0 as address.public;
// Input the amount of microcredits to unbond.
input r1 as u64.public;
// Construct the initial unbond state.
cast 0u64 0u32 into r2 as unbond_state;
// Get the unbond state for the caller, or default to the initial unbond state.
get.or_use unbonding[r0] r2 into r3;
// Compute the height at which the unbonding will be complete, starting from the current block.
// Note: Calling unbond across multiple blocks before the unbonding is complete will reset the height each time.
add block.height 360u32 into r4;
// Determine if the caller is a validator or delegator.
contains committee[r0] into r5;
// If the caller is a validator, jump to the `unbond_validator` logic.
branch.eq r5 true to unbond_validator;
// If the caller is not a validator, jump to the `unbond_delegator` logic.
branch.eq r5 false to unbond_delegator;
/******* Unbond Validator *******/
// Starts the `unbond_validator` logic.
position unbond_validator;
/* Committee */
// Get the committee state for the specified validator.
get committee[r0] into r6;
// Decrement the stake for the specified validator.
sub r6.microcredits r1 into r7;
/* Bonded */
// Get the bond state for the validator, or fail if it does not exist.
get bonded[r0] into r8;
// Ensure that the validator matches in the bond state.
assert.eq r8.validator r0;
// Decrement the microcredits in the bond state.
sub r8.microcredits r1 into r9;
// Determine if the remaining bond is at least one million credits.
gte r9 1_000_000_000_000u64 into r10;
// If the remaining balance is at least 1 million credits, jump to the `decrement_validator` logic.
branch.eq r10 true to decrement_validator;
// If the remaining balance is less than 1 million credits, jump to the `remove_validator` logic.
branch.eq r10 false to remove_validator;
/*** Decrement Validator ***/
// Starts the `decrement_validator` logic.
position decrement_validator;
/* Committee */
// Construct the updated committee state.
cast r7 r6.is_open into r11 as committee_state;
// Update the committee state for the validator.
set r11 into committee[r0];
/* Bonded */
// Construct the updated bond state.
cast r0 r9 into r12 as bond_state;
// Update the bond state for the validator.
set r12 into bonded[r0];
/* Unbonding */
// Increment the microcredits in the unbond state.
add r3.microcredits r1 into r13;
// Construct the updated unbond state.
cast r13 r4 into r14 as unbond_state;
// Update the unbond state for the caller.
set r14 into unbonding[r0];
// Ends the `decrement_validator` logic.
branch.eq true true to end;
/*** Remove Validator ***/
// Starts the `remove_validator` logic.
position remove_validator;
// Ensure that the validator has no delegators.
assert.eq r6.microcredits r8.microcredits;
/* Committee */
// Remove the validator from the committee.
remove committee[r0];
/* Bonded */
// Remove the bond state for the validator.
remove bonded[r0];
/* Unbonding */
// Increment the microcredits in the unbond state.
add r3.microcredits r8.microcredits into r15;
// Construct the updated unbond state.
cast r15 r4 into r16 as unbond_state;
// Update the unbond state for the caller.
set r16 into unbonding[r0];
// Ends the `remove_validator` logic.
branch.eq true true to end;
/******* Unbond Delegator *******/
// Starts the `unbond_delegator` logic.
position unbond_delegator;
// Get the bond state for the caller, or fail if it does not exist.
get bonded[r0] into r17;
// Decrement the microcredits in the bond state.
sub r17.microcredits r1 into r18;
// Determine if the remaining bond is at least 10 credits.
gte r18 10_000_000u64 into r19;
// If the remaining balance is at least 10 credits, jump to the `decrement_delegator` logic.
branch.eq r19 true to decrement_delegator;
// If the remaining balance is less than 10 credits, jump to the `remove_delegator` logic.
branch.eq r19 false to remove_delegator;
/*** Decrement Delegator ***/
// Starts the `decrement_delegator` logic.
position decrement_delegator;
/* Committee */
// Get the stake for the specified validator.
// If the validator does not exist, this finalize scope will fail.
get committee[r17.validator] into r20;
// Decrement the stake for the specified validator.
sub r20.microcredits r1 into r21;
// Construct the updated committee state.
cast r21 r20.is_open into r22 as committee_state;
// Update the stake for the specified validator.
set r22 into committee[r17.validator];
/* Bonded */
// Construct the updated bond state.
cast r17.validator r18 into r23 as bond_state;
// Update the bond state for the caller.
set r23 into bonded[r0];
/* Unbonding */
// Increment the microcredits in the unbond state.
add r3.microcredits r1 into r24;
// Construct the updated unbond state.
cast r24 r4 into r25 as unbond_state;
// Update the unbond state for the caller.
set r25 into unbonding[r0];
// Ends the `decrement_delegator` logic.
branch.eq true true to end;
/*** Remove Delegator ***/
// Starts the `remove_delegator` logic.
position remove_delegator;
/* Committee */
// Get the stake for the specified validator.
// If the validator does not exist, this finalize scope will fail.
get committee[r17.validator] into r26;
// Decrement the stake for the specified validator.
sub r26.microcredits r17.microcredits into r27;
// Construct the updated committee state.
cast r27 r26.is_open into r28 as committee_state;
// Update the stake for the specified validator.
set r28 into committee[r17.validator];
/* Bonded */
// Remove the caller from the bonded mapping.
remove bonded[r0];
/* Unbonding */
// Increment the microcredits in the unbond state.
add r3.microcredits r17.microcredits into r29;
// Construct the updated unbond state.
cast r29 r4 into r30 as unbond_state;
// Update the unbond state for the caller.
set r30 into unbonding[r0];
// The terminus.
position end;
/**********************************************************************************************************************/
// This function allows a validator to unbond any delegator that is bonded to them.
function unbond_delegator_as_validator:
// Input the delegator's address.
input r0 as address.public;
// Unbond the delegator as the validator.
async unbond_delegator_as_validator self.caller r0 into r1;
// Output the finalize future.
output r1 as credits.aleo/unbond_delegator_as_validator.future;
finalize unbond_delegator_as_validator:
// Input the validator's address.
input r0 as address.public;
// Input the delegator's address.
input r1 as address.public;
/* Start Committee */
// Get the committee state for the specified validator.
// If the validator does not exist, this finalize scope will fail.
get committee[r0] into r2;
// Enforce that the validator is closed to stakers.
assert.eq r2.is_open false;
// Check if the delegator is a validator.
contains committee[r1] into r3;
// Enforce the delegator is *not* a validator.
assert.eq r3 false;
/* End Committee */
/* Start Bonded */
// Get the bond state for the delegator, or fail if it does not exist.
get bonded[r1] into r4;
// Enforce that the delegator is bonded to the validator.
assert.eq r4.validator r0;
/* End Bonded */
/* Start Committee */
// Decrement the stake for the specified validator.
sub r2.microcredits r4.microcredits into r5;
// Construct the updated committee state.
cast r5 r2.is_open into r6 as committee_state;
/* End Committee */
/* Start Unbond */
// Construct the initial unbond state.
cast 0u64 0u32 into r7 as unbond_state;
// Get the unbond state for the delegator, or default to the initial unbond state.
get.or_use unbonding[r1] r7 into r8;
// Increment the microcredits in the unbond state.
add r8.microcredits r4.microcredits into r9;
// Compute the height at which the unbonding will be complete, starting from the current block.
// Note: Calling unbond across multiple blocks before the unbonding is complete will reset the height each time.
add block.height 360u32 into r10;
// Construct the updated unbond state.
cast r9 r10 into r11 as unbond_state;
/* End Unbond */
/* Start Writes */
// Update the committee state for the specified validator.
set r6 into committee[r0];
// Remove the bond state for the delegator.
remove bonded[r1];
// Update the unbond state for the delegator.
set r11 into unbonding[r1];
/* End Writes */
/**********************************************************************************************************************/
// This function allows any staker to claim their microcredits after the unbonding period.
function claim_unbond_public:
// Claim the unbonded microcredits.
async claim_unbond_public self.caller into r0;
// Output the finalize future.
output r0 as credits.aleo/claim_unbond_public.future;
finalize claim_unbond_public:
// Input the staker's address.
input r0 as address.public;
// Get the unbond state for the caller, or fail if it does not exist.
get unbonding[r0] into r1;
// Determine if unbonding is complete.
gte block.height r1.height into r2;
// Enforce the unbonding is complete.
assert.eq r2 true;
// Add the unbonded amount to the stakers's public balance.
// Increments `account[r0]` by `r1`.
// If `account[r0]` does not exist, 0u64 is used.
// If `account[r0] + r2` overflows, `claim_unbond_public` is reverted.
get.or_use account[r0] 0u64 into r3;
add r1.microcredits r3 into r4;
set r4 into account[r0];
// Remove the unbond state for the caller.
remove unbonding[r0];
/**********************************************************************************************************************/
// This function allows a validator to set their state to be either opened or closed to stakers.
// When the validator is open to stakers, any staker (including the validator) can bond or unbond from the validator.
// When the validator is closed to stakers, all stakers can only unbond from the validator.
//
// This function serves two primary purposes:
// 1. Allow a validator to leave the committee, by closing themselves to stakers and then unbonding all of their stakers.
// 2. Allow a validator to maintain their % of stake, by closing themselves to allowing more stakers to bond to them.
function set_validator_state:
// Input the 'is_open' state.
input r0 as boolean.public;
// Set the validator to be either open or closed to stakers.
async set_validator_state self.caller r0 into r1;
// Output the finalize future.
output r1 as credits.aleo/set_validator_state.future;
finalize set_validator_state:
// Input the validator's address.
input r0 as address.public;
// Input the 'is_open' state.
input r1 as boolean.public;
// Get the committee state for the specified validator.
// If the validator does not exist, this finalize scope will fail.
get committee[r0] into r2;
// Construct the updated committee state.
cast r2.microcredits r1 into r3 as committee_state;
// Update the committee state for the specified validator.
set r3 into committee[r0];
/**********************************************************************************************************************/
// The `transfer_public` function sends the specified amount
// from the sender's `account` to the receiver's `account`.
function transfer_public:
// Input the receiver.
input r0 as address.public;
// Input the amount.
input r1 as u64.public;
// Transfer the credits publicly.
async transfer_public self.caller r0 r1 into r2;
// Output the finalize future.
output r2 as credits.aleo/transfer_public.future;
finalize transfer_public:
// Input the sender.
input r0 as address.public;
// Input the receiver.
input r1 as address.public;
// Input the amount.
input r2 as u64.public;
// Decrements `account[r0]` by `r2`.
// If `account[r0]` does not exist, 0u64 is used.
// If `account[r0] - r2` underflows, `transfer_public` is reverted.
get.or_use account[r0] 0u64 into r3;
sub r3 r2 into r4;
set r4 into account[r0];
// Increments `account[r1]` by `r2`.
// If `account[r1]` does not exist, 0u64 is used.
// If `account[r1] + r2` overflows, `transfer_public` is reverted.
get.or_use account[r1] 0u64 into r5;
add r5 r2 into r6;
set r6 into account[r1];
/**********************************************************************************************************************/
// The `transfer_private` function sends the specified amount
// from the sender's record to the receiver in a record.
function transfer_private:
// Input the sender's record.
input r0 as credits.record;
// Input the receiver.
input r1 as address.private;
// Input the amount.
input r2 as u64.private;
// Checks the given record has a sufficient amount.
// This `sub` operation is safe, and the proof will fail
// if an underflow occurs. The destination register `r3` holds
// the change amount to be returned to the sender.
sub r0.microcredits r2 into r3;
// Construct a record for the specified receiver.
cast r1 r2 into r4 as credits.record;
// Construct a record with the change amount for the sender.
cast r0.owner r3 into r5 as credits.record;
// Output the receiver's record.
output r4 as credits.record;
// Output the sender's change record.
output r5 as credits.record;
/**********************************************************************************************************************/
// The `transfer_private_to_public` function turns a specified amount
// from a record into public credits for the specified receiver.
//
// This function preserves privacy for the sender's record, however
// it publicly reveals the receiver and the amount.
function transfer_private_to_public:
// Input the sender's record.
input r0 as credits.record;
// Input the receiver.
input r1 as address.public;
// Input the amount.
input r2 as u64.public;
// Checks the given record has a sufficient amount.
// This `sub` operation is safe, and the proof will fail
// if an underflow occurs. The destination register `r3` holds
// the change amount for the sender.
sub r0.microcredits r2 into r3;
// Construct a record with the change amount for the sender.
cast r0.owner r3 into r4 as credits.record;
// Increment the amount publicly for the receiver.
async transfer_private_to_public r1 r2 into r5;
// Output the sender's change record.
output r4 as credits.record;
// Output the finalize future.
output r5 as credits.aleo/transfer_private_to_public.future;
finalize transfer_private_to_public:
// Input the receiver.
input r0 as address.public;
// Input the amount.
input r1 as u64.public;
// Retrieve the balance of the sender.
// If `account[r0]` does not exist, 0u64 is used.
get.or_use account[r0] 0u64 into r2;
// Increments `account[r0]` by `r1`.
// If `r1 + r2` overflows, `transfer_private_to_public` is reverted.
add r1 r2 into r3;
// Updates the balance of the sender.
set r3 into account[r0];
/**********************************************************************************************************************/
// The `transfer_public_to_private` function turns a specified amount
// from the mapping `account` into a record for the specified receiver.
//
// This function publicly reveals the sender, the receiver, and the specified amount.
// However, subsequent methods using the receiver's record can preserve the receiver's privacy.
function transfer_public_to_private:
// Input the receiver.
input r0 as address.private;
// Input the amount.
input r1 as u64.public;
// Construct a record for the receiver.
cast r0 r1 into r2 as credits.record;
// Decrement the balance of the sender publicly.
async transfer_public_to_private self.caller r1 into r3;
// Output the record of the receiver.
output r2 as credits.record;
// Output the finalize future.
output r3 as credits.aleo/transfer_public_to_private.future;
finalize transfer_public_to_private:
// Input the sender.
input r0 as address.public;
// Input the amount.
input r1 as u64.public;
// Retrieve the balance of the sender.
// If `account[r0]` does not exist, 0u64 is used.
get.or_use account[r0] 0u64 into r2;
// Decrements `account[r0]` by `r1`.
// If `r2 - r1` underflows, `transfer_public_to_private` is reverted.
sub r2 r1 into r3;
// Updates the balance of the sender.
set r3 into account[r0];
/**********************************************************************************************************************/
// The `join` function combines two records into one.
function join:
// Input the first record.
input r0 as credits.record;
// Input the second record.
input r1 as credits.record;
// Combines the amount of the first record and the second record.
// This `add` operation is safe, and the proof will fail
// if an overflow occurs.
add r0.microcredits r1.microcredits into r2;
// Construct a record with the combined amount.
cast r0.owner r2 into r3 as credits.record;
// Output the record.
output r3 as credits.record;
/**********************************************************************************************************************/
// The `split` function splits a record into two records. The given input amount will be stored in the first record,
// and the remaining amount will be stored in the second record, with the fee deducted from the remaining amount.
// If the caller executes a transaction that contains only a call to this function, then the transaction does not
// require a fee, unless the caller wishes to provide an additional fee. Transactions that contain multiple transitions
// (that include one or more calls to this function) will require a fee as per standard consensus rules.
function split:
// Input the record.
input r0 as credits.record;
// Input the amount to split.
input r1 as u64.private;
// Checks the given record has a sufficient amount to split.
// This `sub` operation is safe, and the proof will fail
// if an underflow occurs.
sub r0.microcredits r1 into r2;
// Checks the given record has a sufficient fee to remove.
// This `sub` operation is safe, and the proof will fail
// if an underflow occurs.
sub r2 10_000u64 into r3;
// Construct the first record.
cast r0.owner r1 into r4 as credits.record;
// Construct the second record.
cast r0.owner r3 into r5 as credits.record;
// Output the first record.
output r4 as credits.record;
// Output the second record.
output r5 as credits.record;
/**********************************************************************************************************************/
// The `fee_private` function charges the specified amount from the sender's record.
function fee_private:
// Input the sender's record.
input r0 as credits.record;
// Input the amount.
input r1 as u64.public;
// Input the deployment or execution root.
input r2 as field.public;
// Ensure the amount is nonzero.
assert.neq r1 0u64;
// Ensure the deployment or execution root is nonzero.
assert.neq r2 0field;
// Checks the given record has a sufficient amount.
// This `sub` operation is safe, and the proof will fail
// if an underflow occurs. The destination register `r3` holds
// the change amount for the sender.
sub r0.microcredits r1 into r3;
// Construct a record with the change amount for the sender.
cast r0.owner r3 into r4 as credits.record;
// Output the sender's change record.
output r4 as credits.record;
/**********************************************************************************************************************/
// The `fee_public` function charges the specified amount from the sender's account.
function fee_public:
// Input the amount.
input r0 as u64.public;
// Input the deployment or execution root.
input r1 as field.public;
// Ensure the amount is nonzero.
assert.neq r0 0u64;
// Ensure the deployment or execution root is nonzero.
assert.neq r1 0field;
// Decrement the balance of the sender publicly.
async fee_public self.caller r0 into r2;
// Output the finalize future.
output r2 as credits.aleo/fee_public.future;
finalize fee_public:
// Input the sender's address.
input r0 as address.public;
// Input the amount.
input r1 as u64.public;
// Retrieve the balance of the sender.
// If `account[r0]` does not exist, `fee_public` is reverted.
get account[r0] into r2;
// Decrements `account[r0]` by `r1`.
// If `r2 - r1` underflows, `fee_public` is reverted.
sub r2 r1 into r3;
// Updates the balance of the sender.
set r3 into account[r0];
/**********************************************************************************************************************/
// Open Questions:
// fn bond
// - if the bond is now 33% or more, close the validator. (determine how hard to impl this)
/**********************************************************************************************************************/

View File

@ -0,0 +1,242 @@
import credits.aleo;
program large_functions.aleo;
function join_3:
input r0 as credits.aleo/credits.record;
input r1 as credits.aleo/credits.record;
input r2 as credits.aleo/credits.record;
assert.eq r0.owner r1.owner;
assert.eq r1.owner r2.owner;
call credits.aleo/join r0 r1 into r3;
call credits.aleo/join r3 r2 into r4;
output r4 as credits.aleo/credits.record;
function join_5:
input r0 as credits.aleo/credits.record;
input r1 as credits.aleo/credits.record;
input r2 as credits.aleo/credits.record;
input r3 as credits.aleo/credits.record;
input r4 as credits.aleo/credits.record;
assert.eq r0.owner r1.owner;
assert.eq r1.owner r2.owner;
assert.eq r2.owner r3.owner;
assert.eq r3.owner r4.owner;
call credits.aleo/join r0 r1 into r5;
call credits.aleo/join r2 r3 into r6;
call credits.aleo/join r5 r6 into r7;
call credits.aleo/join r7 r4 into r8;
output r8 as credits.aleo/credits.record;
function join6:
input r0 as credits.aleo/credits.record;
input r1 as credits.aleo/credits.record;
input r2 as credits.aleo/credits.record;
input r3 as credits.aleo/credits.record;
input r4 as credits.aleo/credits.record;
input r5 as credits.aleo/credits.record;
assert.eq r0.owner r1.owner;
assert.eq r1.owner r2.owner;
assert.eq r2.owner r3.owner;
assert.eq r3.owner r4.owner;
assert.eq r4.owner r5.owner;
call credits.aleo/join r0 r1 into r6;
call credits.aleo/join r2 r3 into r7;
call credits.aleo/join r4 r5 into r8;
call credits.aleo/join r6 r7 into r9;
call credits.aleo/join r9 r8 into r10;
output r10 as credits.aleo/credits.record;
function join7:
input r0 as credits.aleo/credits.record;
input r1 as credits.aleo/credits.record;
input r2 as credits.aleo/credits.record;
input r3 as credits.aleo/credits.record;
input r4 as credits.aleo/credits.record;
input r5 as credits.aleo/credits.record;
input r6 as credits.aleo/credits.record;
assert.eq r0.owner r1.owner;
assert.eq r1.owner r2.owner;
assert.eq r2.owner r3.owner;
assert.eq r3.owner r4.owner;
assert.eq r4.owner r5.owner;
assert.eq r5.owner r6.owner;
call credits.aleo/join r0 r1 into r7;
call credits.aleo/join r2 r3 into r8;
call credits.aleo/join r4 r5 into r9;
call credits.aleo/join r7 r8 into r10;
call credits.aleo/join r10 r9 into r11;
call credits.aleo/join r11 r6 into r12;
output r12 as credits.aleo/credits.record;
function join8:
input r0 as credits.aleo/credits.record;
input r1 as credits.aleo/credits.record;
input r2 as credits.aleo/credits.record;
input r3 as credits.aleo/credits.record;
input r4 as credits.aleo/credits.record;
input r5 as credits.aleo/credits.record;
input r6 as credits.aleo/credits.record;
input r7 as credits.aleo/credits.record;
assert.eq r0.owner r1.owner;
assert.eq r1.owner r2.owner;
assert.eq r2.owner r3.owner;
assert.eq r3.owner r4.owner;
assert.eq r4.owner r5.owner;
assert.eq r5.owner r6.owner;
assert.eq r6.owner r7.owner;
call credits.aleo/join r0 r1 into r8;
call credits.aleo/join r2 r3 into r9;
call credits.aleo/join r4 r5 into r10;
call credits.aleo/join r6 r7 into r11;
call credits.aleo/join r8 r9 into r12;
call credits.aleo/join r11 r10 into r13;
call credits.aleo/join r12 r13 into r14;
output r14 as credits.aleo/credits.record;
function join9:
input r0 as credits.aleo/credits.record;
input r1 as credits.aleo/credits.record;
input r2 as credits.aleo/credits.record;
input r3 as credits.aleo/credits.record;
input r4 as credits.aleo/credits.record;
input r5 as credits.aleo/credits.record;
input r6 as credits.aleo/credits.record;
input r7 as credits.aleo/credits.record;
input r8 as credits.aleo/credits.record;
assert.eq r0.owner r1.owner;
assert.eq r1.owner r2.owner;
assert.eq r2.owner r3.owner;
assert.eq r3.owner r4.owner;
assert.eq r4.owner r5.owner;
assert.eq r5.owner r6.owner;
assert.eq r6.owner r7.owner;
assert.eq r7.owner r8.owner;
call credits.aleo/join r0 r1 into r9;
call credits.aleo/join r2 r3 into r10;
call credits.aleo/join r4 r5 into r11;
call credits.aleo/join r6 r7 into r12;
call credits.aleo/join r9 r10 into r13;
call credits.aleo/join r12 r11 into r14;
call credits.aleo/join r13 r14 into r15;
call credits.aleo/join r15 r8 into r16;
output r16 as credits.aleo/credits.record;
function join10:
input r0 as credits.aleo/credits.record;
input r1 as credits.aleo/credits.record;
input r2 as credits.aleo/credits.record;
input r3 as credits.aleo/credits.record;
input r4 as credits.aleo/credits.record;
input r5 as credits.aleo/credits.record;
input r6 as credits.aleo/credits.record;
input r7 as credits.aleo/credits.record;
input r8 as credits.aleo/credits.record;
input r9 as credits.aleo/credits.record;
assert.eq r0.owner r1.owner;
assert.eq r1.owner r2.owner;
assert.eq r2.owner r3.owner;
assert.eq r3.owner r4.owner;
assert.eq r4.owner r5.owner;
assert.eq r5.owner r6.owner;
assert.eq r6.owner r7.owner;
assert.eq r7.owner r8.owner;
assert.eq r8.owner r9.owner;
call credits.aleo/join r0 r1 into r10;
call credits.aleo/join r2 r3 into r11;
call credits.aleo/join r4 r5 into r12;
call credits.aleo/join r6 r7 into r13;
call credits.aleo/join r8 r9 into r14;
call credits.aleo/join r10 r11 into r15;
call credits.aleo/join r13 r12 into r16;
call credits.aleo/join r15 r16 into r17;
call credits.aleo/join r17 r14 into r18;
output r18 as credits.aleo/credits.record;
function transfer_3:
input r0 as address.private;
input r1 as credits.aleo/credits.record;
input r2 as credits.aleo/credits.record;
input r3 as credits.aleo/credits.record;
assert.eq r1.owner r2.owner;
assert.eq r2.owner r3.owner;
call credits.aleo/transfer_private r1 r0 r1.microcredits into r4 r5;
call credits.aleo/transfer_private r2 r0 r2.microcredits into r6 r7;
call credits.aleo/transfer_private r3 r0 r3.microcredits into r8 r9;
output r4 as credits.aleo/credits.record;
output r5 as credits.aleo/credits.record;
output r6 as credits.aleo/credits.record;
output r7 as credits.aleo/credits.record;
output r8 as credits.aleo/credits.record;
output r9 as credits.aleo/credits.record;
function transfer_5:
input r0 as address.private;
input r1 as credits.aleo/credits.record;
input r2 as credits.aleo/credits.record;
input r3 as credits.aleo/credits.record;
input r4 as credits.aleo/credits.record;
input r5 as credits.aleo/credits.record;
assert.eq r1.owner r2.owner;
assert.eq r2.owner r3.owner;
assert.eq r3.owner r4.owner;
assert.eq r4.owner r5.owner;
call credits.aleo/transfer_private r1 r0 r1.microcredits into r6 r7;
call credits.aleo/transfer_private r2 r0 r2.microcredits into r8 r9;
call credits.aleo/transfer_private r3 r0 r3.microcredits into r10 r11;
call credits.aleo/transfer_private r4 r0 r4.microcredits into r12 r13;
call credits.aleo/transfer_private r5 r0 r5.microcredits into r14 r15;
output r6 as credits.aleo/credits.record;
output r7 as credits.aleo/credits.record;
output r8 as credits.aleo/credits.record;
output r9 as credits.aleo/credits.record;
output r10 as credits.aleo/credits.record;
output r11 as credits.aleo/credits.record;
output r12 as credits.aleo/credits.record;
output r13 as credits.aleo/credits.record;
output r14 as credits.aleo/credits.record;
output r15 as credits.aleo/credits.record;
function split_3:
input r0 as u64.private;
input r1 as credits.aleo/credits.record;
input r2 as credits.aleo/credits.record;
input r3 as credits.aleo/credits.record;
assert.eq r1.owner r2.owner;
assert.eq r2.owner r3.owner;
call credits.aleo/split r1 r0 into r4 r5;
call credits.aleo/split r2 r0 into r6 r7;
call credits.aleo/split r3 r0 into r8 r9;
output r4 as credits.aleo/credits.record;
output r5 as credits.aleo/credits.record;
output r6 as credits.aleo/credits.record;
output r7 as credits.aleo/credits.record;
output r8 as credits.aleo/credits.record;
output r9 as credits.aleo/credits.record;
function split_5:
input r0 as u64.private;
input r1 as credits.aleo/credits.record;
input r2 as credits.aleo/credits.record;
input r3 as credits.aleo/credits.record;
input r4 as credits.aleo/credits.record;
input r5 as credits.aleo/credits.record;
assert.eq r1.owner r2.owner;
assert.eq r2.owner r3.owner;
assert.eq r3.owner r4.owner;
assert.eq r4.owner r5.owner;
call credits.aleo/split r1 r0 into r6 r7;
call credits.aleo/split r2 r0 into r8 r9;
call credits.aleo/split r3 r0 into r10 r11;
call credits.aleo/split r4 r0 into r12 r13;
call credits.aleo/split r5 r0 into r14 r15;
output r6 as credits.aleo/credits.record;
output r7 as credits.aleo/credits.record;
output r8 as credits.aleo/credits.record;
output r9 as credits.aleo/credits.record;
output r10 as credits.aleo/credits.record;
output r11 as credits.aleo/credits.record;
output r12 as credits.aleo/credits.record;
output r13 as credits.aleo/credits.record;
output r14 as credits.aleo/credits.record;
output r15 as credits.aleo/credits.record;