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

Compile erc-20 #172

Merged
merged 1 commit into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
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
70 changes: 70 additions & 0 deletions compilation/prepare-contract.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/bin/bash

# This should run in the repository root
# It expects two args: the contract path and the arguments for the init function.

set -e

UKM_CONTRACTS_TESTING_INPUT_DIR=tests/ukm-contracts
UKM_PREPROCESSING_KOMPILED=.build/ukm-preprocessing-kompiled
TEMP_DIR=tmp

mkdir -p $TEMP_DIR

echo "<(<" > $TEMP_DIR/input.tmp
echo "::address" >> $TEMP_DIR/input.tmp
echo "<|>" >> $TEMP_DIR/input.tmp
cat $UKM_CONTRACTS_TESTING_INPUT_DIR/address.rs >> $TEMP_DIR/input.tmp
echo ">)>" >> $TEMP_DIR/input.tmp

echo "<(<" >> $TEMP_DIR/input.tmp
echo "::bytes_hooks" >> $TEMP_DIR/input.tmp
echo "<|>" >> $TEMP_DIR/input.tmp
cat $UKM_CONTRACTS_TESTING_INPUT_DIR/bytes_hooks.rs >> $TEMP_DIR/input.tmp
echo ">)>" >> $TEMP_DIR/input.tmp

echo "<(<" >> $TEMP_DIR/input.tmp
echo "::test_helpers" >> $TEMP_DIR/input.tmp
echo "<|>" >> $TEMP_DIR/input.tmp
cat $UKM_CONTRACTS_TESTING_INPUT_DIR/test_helpers.rs >> $TEMP_DIR/input.tmp
echo ">)>" >> $TEMP_DIR/input.tmp

echo "<(<" >> $TEMP_DIR/input.tmp
echo "::helpers" >> $TEMP_DIR/input.tmp
echo "<|>" >> $TEMP_DIR/input.tmp
cat $UKM_CONTRACTS_TESTING_INPUT_DIR/helpers.rs >> $TEMP_DIR/input.tmp
echo ">)>" >> $TEMP_DIR/input.tmp

echo "<(<" >> $TEMP_DIR/input.tmp
echo "::state_hooks" >> $TEMP_DIR/input.tmp
echo "<|>" >> $TEMP_DIR/input.tmp
cat $UKM_CONTRACTS_TESTING_INPUT_DIR/state_hooks.rs >> $TEMP_DIR/input.tmp
echo ">)>" >> $TEMP_DIR/input.tmp

echo "<(<" >> $TEMP_DIR/input.tmp
echo "::single_value_mapper" >> $TEMP_DIR/input.tmp
echo "<|>" >> $TEMP_DIR/input.tmp
cat $UKM_CONTRACTS_TESTING_INPUT_DIR/single_value_mapper.rs >> $TEMP_DIR/input.tmp
echo ">)>" >> $TEMP_DIR/input.tmp

echo "<(<" >> $TEMP_DIR/input.tmp
echo "::ukm" >> $TEMP_DIR/input.tmp
echo "<|>" >> $TEMP_DIR/input.tmp
cat $UKM_CONTRACTS_TESTING_INPUT_DIR/ukm.rs >> $TEMP_DIR/input.tmp
echo ">)>" >> $TEMP_DIR/input.tmp

echo "<(<" >> $TEMP_DIR/input.tmp
echo "$1" | sed 's%^.*/%%' | sed 's/\..*//' | sed 's/^/::/' >> $TEMP_DIR/input.tmp
echo "<|>" >> $TEMP_DIR/input.tmp
cat "$1" >> $TEMP_DIR/input.tmp
echo ">)>" >> $TEMP_DIR/input.tmp

krun \
$TEMP_DIR/input.tmp \
--parser $(pwd)/parsers/crates-ukm-preprocessing-execution.sh \
--definition $UKM_PREPROCESSING_KOMPILED \
--output kore \
--output-file $TEMP_DIR/output.kore \

echo "not finished, must extract the bytes from the result: $TEMP_DIR/output.kore"
false
7 changes: 7 additions & 0 deletions compilation/prepare-erc20.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash

# This should run in the repository root

set -e

compilation/prepare-contract.sh tests/ukm-contracts/erc_20_token.rs "1000000000000000000_u256,"
13 changes: 13 additions & 0 deletions parsers/args-ukm-preprocessing-execution.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#! /bin/bash

function parse_args() {
kast \
--output kore \
--definition $1 \
--module RUST-CRATES-SYNTAX \
--sort ArgumentList \
$2
}

parse_args .build/ukm-preprocessing-kompiled $1

5 changes: 5 additions & 0 deletions parsers/crates-ukm-preprocessing-execution.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#! /bin/bash

source ${BASH_SOURCE%/*}/inc-crates.sh

parse_crates .build/ukm-preprocessing-kompiled $1
97 changes: 51 additions & 46 deletions tests/ukm-contracts/erc_20_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// https://github.com/Pi-Squared-Inc/pi2-examples/blob/b63d0a78922874a486be8a0395a627425fb5a052/solidity/src/tokens/SomeToken.sol
//
// The main change is that the contract does not issue specific error objects
// (e.g. ERC20InsufficientBalance), it just calls `require!` with various
// (e.g. ERC20InsufficientBalance), it just calls `::helpers::require` with various
// (string) explanations.
//
// Also, the `totalSupply` endpoint is declared implicitely as a view for
Expand All @@ -22,45 +22,45 @@ TODOs:
inits;
- Support some sort of struct for implementing MessageResult within the UKM module.
We also have to figure out the contents of MessageResult.

Observations:
- ManagedAddress was replaced by an integer to fit the behaviors of UKM;

---------------------------------------------------------------------------- */

#[ukm::contract]
pub trait Erc20Token {
#[view(totalSupply)]
// #[view(totalSupply)]
#[storage_mapper("total_supply")]
fn s_total_supply(&self) -> SingleValueMapper<u64>;
fn s_total_supply(&self) -> ::single_value_mapper::SingleValueMapper<u256>;

#[view(getName)]
// #[view(getName)]
#[storage_mapper("name")]
fn s_name(&self) -> SingleValueMapper<ManagedBuffer>;
fn s_name(&self) -> ::single_value_mapper::SingleValueMapper<ManagedBuffer>;

#[view(getSymbol)]
// #[view(getSymbol)]
#[storage_mapper("symbol")]
fn s_symbol(&self) -> SingleValueMapper<ManagedBuffer>;
fn s_symbol(&self) -> ::single_value_mapper::SingleValueMapper<ManagedBuffer>;

#[view(getBalances)]
// #[view(getBalances)]
#[storage_mapper("balances")]
fn s_balances(&self, address: u64) -> SingleValueMapper<u64>;
fn s_balances(&self, address: u160) -> ::single_value_mapper::SingleValueMapper<u256>;

#[view(getAllowances)]
// #[view(getAllowances)]
#[storage_mapper("balances")]
fn s_allowances(&self, account: u64, spender: u64) -> SingleValueMapper<u64>;
fn s_allowances(&self, account: u160, spender: u160) -> ::single_value_mapper::SingleValueMapper<u256>;

#[event("Transfer")]
fn transfer_event(&self, #[indexed] from: u64, #[indexed] to: u64, value: u64);
fn transfer_event(&self, #[indexed] from: u160, #[indexed] to: u160, value: u256);

#[event("Approval")]
fn approval_event(&self, #[indexed] owner: u64, #[indexed] spender: u64, value: u64);
fn approval_event(&self, #[indexed] owner: u160, #[indexed] spender: u160, value: u256);


#[init]
fn init(&self, name: &ManagedBuffer, symbol: &ManagedBuffer, init_supply: u64) {
self.s_name().set_if_empty(name);
self.s_symbol().set_if_empty(symbol);
fn init(&self, /*name: &ManagedBuffer, symbol: &ManagedBuffer, */init_supply: u256) {
// self.s_name().set_if_empty(name);
// self.s_symbol().set_if_empty(symbol);
self._mint(::ukm::Caller(), init_supply);
}

Expand All @@ -72,88 +72,93 @@ pub trait Erc20Token {
18
}

#[view(name)]
fn name(&self) -> ManagedBuffer {
self.s_name().get()
#[view(totalSupply)]
fn total_supply(&self) -> u256 {
self.s_total_supply().get()
}

#[view(symbol)]
fn symbol(&self) -> ManagedBuffer {
self.s_symbol().get()
}
// #[view(name)]
// fn name(&self) -> ManagedBuffer {
// self.s_name().get()
// }

// #[view(symbol)]
// fn symbol(&self) -> ManagedBuffer {
// self.s_symbol().get()
// }

#[view(balanceOf)]
fn balance_of(&self, account: u64) -> u64 {
fn balance_of(&self, account: u160) -> u256 {
self.s_balances(account).get()
}

#[endpoint(transfer)]
fn transfer(&self, to: u64, value: u64) -> bool {
fn transfer(&self, to: u160, value: u256) -> bool {
let owner = ::ukm::Caller();
self._transfer(&owner, to, &value);
true
}

#[view(allowance)]
fn allowance(&self, owner: u64, spender: u64) -> u64 {
fn allowance(&self, owner: u160, spender: u160) -> u256 {
self.s_allowances(owner, spender).get()
}

#[endpoint(approve)]
fn approve(&self, spender: u64, value: u64) -> bool {
fn approve(&self, spender: u160, value: u256) -> bool {
let owner = ::ukm::Caller();
self._approve(&owner, spender, value, true);
true
}

#[endpoint(transferFrom)]
fn transfer_from(&self, from: u64, to: u64, value: u64) -> bool {
fn transfer_from(&self, from: u160, to: u160, value: u256) -> bool {
let spender = ::ukm::Caller();
self._spend_allowance(from, &spender, value);
self._transfer(from, to, value);
true
}

fn _transfer(&self, from: u64, to: u64, value: u64) {
require!(!from.is_zero(), "Invalid sender");
require!(!to.is_zero(), "Invalid receiver");
fn _transfer(&self, from: u160, to: u160, value: u256) {
::helpers::require(!::address::is_zero(from), "Invalid sender");
::helpers::require(!::address::is_zero(to), "Invalid receiver");
self._update(from, to, value);
self.transfer_event(from, to, value);
}

fn _update(&self, from: u64, to: u64, value: u64) {
if from.is_zero() {
fn _update(&self, from: u160, to: u160, value: u256) {
if ::address::is_zero(from) {
self.s_total_supply().set(self.s_total_supply().get() + value);
} else {
let from_balance = self.s_balances(from).get();
require!(value <= &from_balance, "Insufficient balance");
::helpers::require(value <= &from_balance, "Insufficient balance");
self.s_balances(from).set(self.s_balances(from).get() - value);
};

if to.is_zero() {
if ::address::is_zero(to) {
self.s_total_supply().set(self.s_total_supply().get() - value);
} else {
self.s_balances(to).set(self.s_balances(to).get() + value);
}
}

fn _mint(&self, account: u64, value: u64) {
require!(!account.is_zero(), "Zero address");
self._update(0_u64, account, value);
fn _mint(&self, account: u160, value: u256) {
::helpers::require(!::address::is_zero(account), "Zero address");
self._update(0_u160, account, value);
}

fn _approve(&self, owner: u64, spender: u64, value: u64, emit_event: bool) {
require!(!owner.is_zero(), "Invalid approver");
require!(!spender.is_zero(), "Invalid spender");
fn _approve(&self, owner: u160, spender: u160, value: u256, emit_event: bool) {
::helpers::require(!::address::is_zero(owner), "Invalid approver");
::helpers::require(!::address::is_zero(spender), "Invalid spender");
self.s_allowances(owner, spender).set(value);
if emit_event {
self.approval_event(owner, spender, value);
}
}

fn _spend_allowance(&self, owner: u64, spender: u64, value: u64) {
fn _spend_allowance(&self, owner: u160, spender: u160, value: u256) {
let current_allowance = self.allowance(owner, spender);
require!(value <= &current_allowance, "Insuficient allowance");
::helpers::require(value <= &current_allowance, "Insuficient allowance");
self._approve(owner, spender, &(current_allowance - value), false);
}

Expand Down
Loading