Skip to content

Commit

Permalink
Merge pull request #1 from Cardinal-Cryptography/init
Browse files Browse the repository at this point in the history
Initial implementation
  • Loading branch information
h4nsu authored Sep 29, 2023
2 parents 8f42659 + dfb9306 commit d12998c
Show file tree
Hide file tree
Showing 4 changed files with 403 additions and 0 deletions.
24 changes: 24 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "psp22"
version = "0.1.0"
authors = ["Hans <michal.handzlik@cardinals.cc>"]
edition = "2021"

[dependencies]
ink = { version = "4.3", default-features = false }

scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2.9", default-features = false, features = ["derive"], optional = true }

[lib]
path = "lib.rs"

[features]
default = ["std"]
std = [
"ink/std",
"scale/std",
"scale-info/std",
]
contract = []
ink-as-dependency = []
220 changes: 220 additions & 0 deletions lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
#![cfg_attr(not(feature = "std"), no_std, no_main)]

mod traits;
mod types;

pub use traits::PSP22;
pub use types::{PSP22Data, PSP22Error};

#[cfg(feature = "contract")]
#[ink::contract]
mod token {
use crate::traits::PSP22;
use crate::types::{PSP22Data, PSP22Error};

#[ink(storage)]
pub struct Token {
data: PSP22Data,
}

impl Token {
#[ink(constructor)]
pub fn new(supply: u128) -> Self {
Self {
data: PSP22Data::new(supply, Self::env().caller()),
}
}
}

#[ink(event)]
pub struct Approval {
#[ink(topic)]
owner: AccountId,
#[ink(topic)]
spender: AccountId,
amount: u128,
}

#[ink(event)]
pub struct Transfer {
#[ink(topic)]
from: AccountId,
#[ink(topic)]
to: AccountId,
value: u128,
}

impl PSP22 for Token {
#[ink(message)]
fn total_supply(&self) -> u128 {
self.data.total_supply
}

#[ink(message)]
fn balance_of(&self, owner: AccountId) -> u128 {
self.data.balances.get(owner).unwrap_or_default()
}

#[ink(message)]
fn allowance(&self, owner: AccountId, spender: AccountId) -> u128 {
self.data
.allowances
.get((owner, spender))
.unwrap_or_default()
}

#[ink(message)]
fn transfer(
&mut self,
to: AccountId,
value: u128,
_data: ink::prelude::vec::Vec<u8>,
) -> Result<(), PSP22Error> {
let from = self.env().caller();
if from == to || value == 0 {
return Ok(());
}
let from_balance = self.balance_of(from);
if from_balance < value {
return Err(PSP22Error::InsufficientBalance);
}

if from_balance == value {
self.data.balances.remove(from);
} else {
self.data
.balances
.insert(from, &(from_balance.saturating_sub(value)));
}
let to_balance = self.balance_of(to);
// Total supply is limited by u128.MAX so no overflow is possible
self.data
.balances
.insert(to, &(to_balance.saturating_add(value)));
self.env().emit_event(Transfer { from, to, value });
Ok(())
}

#[ink(message)]
fn transfer_from(
&mut self,
from: AccountId,
to: AccountId,
value: u128,
data: ink::prelude::vec::Vec<u8>,
) -> Result<(), PSP22Error> {
if from == to || value == 0 {
return Ok(());
}
let caller = self.env().caller();
if caller == from {
return self.transfer(to, value, data);
}

let allowance = self.allowance(from, caller);
if allowance < value {
return Err(PSP22Error::InsufficientAllowance);
}
let from_balance = self.balance_of(from);
if from_balance < value {
return Err(PSP22Error::InsufficientBalance);
}

if allowance == value {
self.data.allowances.remove((from, caller));
} else {
self.data
.allowances
.insert((from, caller), &(allowance.saturating_sub(value)));
}

if from_balance == value {
self.data.balances.remove(from);
} else {
self.data
.balances
.insert(from, &(from_balance.saturating_sub(value)));
}
let to_balance = self.balance_of(to);
// Total supply is limited by u128.MAX so no overflow is possible
self.data
.balances
.insert(to, &(to_balance.saturating_add(value)));
self.env().emit_event(Approval {
owner: from,
spender: caller,
amount: allowance.saturating_sub(value),
});
self.env().emit_event(Transfer { from, to, value });
Ok(())
}

#[ink(message)]
fn approve(&mut self, spender: AccountId, value: u128) -> Result<(), PSP22Error> {
let owner = self.env().caller();
if owner == spender {
return Ok(());
}
if value == 0 {
self.data.allowances.remove((owner, spender));
} else {
self.data.allowances.insert((owner, spender), &value);
}
self.env().emit_event(Approval {
owner,
spender,
amount: value,
});
Ok(())
}

#[ink(message)]
fn increase_allowance(
&mut self,
spender: AccountId,
delta_value: u128,
) -> Result<(), PSP22Error> {
let owner = self.env().caller();
if owner == spender || delta_value == 0 {
return Ok(());
}
let allowance = self.allowance(owner, spender);
let amount = allowance.saturating_add(delta_value);
self.data.allowances.insert((owner, spender), &amount);
self.env().emit_event(Approval {
owner,
spender,
amount,
});
Ok(())
}

#[ink(message)]
fn decrease_allowance(
&mut self,
spender: AccountId,
delta_value: u128,
) -> Result<(), PSP22Error> {
let owner = self.env().caller();
if owner == spender || delta_value == 0 {
return Ok(());
}
let allowance = self.allowance(owner, spender);
if allowance < delta_value {
return Err(PSP22Error::InsufficientAllowance);
}
let amount = allowance.saturating_sub(delta_value);
if amount == 0 {
self.data.allowances.remove((owner, spender));
} else {
self.data.allowances.insert((owner, spender), &amount);
}
self.env().emit_event(Approval {
owner,
spender,
amount,
});
Ok(())
}
}
}
121 changes: 121 additions & 0 deletions traits.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
use ink::{prelude::vec::Vec, primitives::AccountId};

use crate::types::PSP22Error;

#[ink::trait_definition]
pub trait PSP22 {
/// Returns the total token supply.
#[ink(message)]
fn total_supply(&self) -> u128;

/// Returns the account balance for the specified `owner`.
///
/// Returns `0` if the account is non-existent.
#[ink(message)]
fn balance_of(&self, owner: AccountId) -> u128;

/// Returns the amount which `spender` is still allowed to withdraw from `owner`.
///
/// Returns `0` if no allowance has been set.
#[ink(message)]
fn allowance(&self, owner: AccountId, spender: AccountId) -> u128;

/// Transfers `value` amount of tokens from the caller's account to account `to`
/// with additional `data` in unspecified format.
///
/// # Events
///
/// On success a `Transfer` event is emitted.
///
/// No-op if the caller and `to` is the same address or `value` is zero, returns success
/// and no events are emitted.
///
/// # Errors
///
/// Reverts with `InsufficientBalance` if the `value` exceeds the caller's balance.
#[ink(message)]
fn transfer(&mut self, to: AccountId, value: u128, data: Vec<u8>) -> Result<(), PSP22Error>;

/// Transfers `value` tokens on the behalf of `from` to the account `to`
/// with additional `data` in unspecified format.
///
/// If `from` and the caller are different addresses, the caller must be allowed
/// by `from` to spend at least `value` tokens.
///
/// # Events
///
/// On success a `Transfer` event is emitted.
///
/// No-op if `from` and `to` is the same address or `value` is zero, returns success
/// and no events are emitted.
///
/// If `from` and the caller are different addresses, a successful transfer results
/// in decreased allowance by `from` to the caller and an `Approval` event with
/// the new allowance amount is emitted.
///
/// # Errors
///
/// Reverts with `InsufficientBalance` if the `value` exceeds the balance of the account `from`.
///
/// Reverts with `InsufficientAllowance` if `from` and the caller are different addresses and
/// the `value` exceeds the allowance granted by `from` to the caller.
///
/// If conditions for both `InsufficientBalance` and `InsufficientAllowance` errors are met,
/// reverts with `InsufficientAllowance`.
#[ink(message)]
fn transfer_from(
&mut self,
from: AccountId,
to: AccountId,
value: u128,
data: Vec<u8>,
) -> Result<(), PSP22Error>;

/// Allows `spender` to withdraw from the caller's account multiple times, up to
/// the total amount of `value`.
///
/// Successive calls of this method overwrite previous values.
///
/// # Events
///
/// An `Approval` event is emitted.
///
/// No-op if the caller and `spender` is the same address, returns success and no events are emitted.
#[ink(message)]
fn approve(&mut self, spender: AccountId, value: u128) -> Result<(), PSP22Error>;

/// Increases by `delta-value` the allowance granted to `spender` by the caller.
///
/// # Events
///
/// An `Approval` event with the new allowance amount is emitted.
///
/// No-op if the caller and `spender` is the same address or `delta-value` is zero, returns success
/// and no events are emitted.
#[ink(message)]
fn increase_allowance(
&mut self,
spender: AccountId,
delta_value: u128,
) -> Result<(), PSP22Error>;

/// Decreases by `delta-value` the allowance granted to `spender` by the caller.
///
/// # Events
///
/// An `Approval` event with the new allowance amount is emitted.
///
/// No-op if the caller and `spender` is the same address or `delta-value` is zero, returns success
/// and no events are emitted.
///
/// # Errors
///
/// Reverts with `InsufficientAllowance` if `spender` and the caller are different addresses and
/// the `delta-value` exceeds the allowance granted by the caller to `spender`.
#[ink(message)]
fn decrease_allowance(
&mut self,
spender: AccountId,
delta_value: u128,
) -> Result<(), PSP22Error>;
}
Loading

0 comments on commit d12998c

Please sign in to comment.