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 traits and function implementations for missing extensions #14

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ Cargo.lock

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

.idea
113 changes: 113 additions & 0 deletions data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use ink::{
primitives::AccountId,
storage::Mapping,
};
use ink::env::call::{build_call, ExecutionInput, Selector};
use ink::env::DefaultEnvironment;

/// Temporary type for events emitted during operations that change the
/// state of PSP22Data struct.
Expand Down Expand Up @@ -267,4 +269,115 @@ impl PSP22Data {
value,
}])
}

/// Burns `value` tokens from `from` account.
pub fn burn_from(&mut self,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of code in this function replicates fn burn - the only additional place here is the check and modification of allowances - so I'd change to code to reuse fn burn (i.e. call it and only add necessary allowances management around it).

caller: AccountId,
from: AccountId,
value: u128
) -> Result<Vec<PSP22Event>, PSP22Error> {
if value == 0 {
return Ok(vec![]);
}
let allowance = self.allowance(from, caller);
if allowance < value {
return Err(PSP22Error::InsufficientAllowance);
}
let balance = self.balance_of(from);
if balance < value {
return Err(PSP22Error::InsufficientBalance);
}

if allowance == value {
self.allowances.remove((from, caller));
} else {
self.allowances
.insert((from, caller), &(allowance.saturating_sub(value)));
}
if balance == value {
self.balances.remove(from);
} else {
self.balances.insert(from, &(balance.saturating_sub(value)));
}
self.total_supply = self.total_supply.saturating_sub(value);
Ok(vec![PSP22Event::Transfer {
from: Some(from),
to: None,
value,
}])
}

/// Deposits a specified amount of tokens from the `underlying` token contract to this contract.
///
/// This method transfers tokens from `sender` to the `contract` account (the current contract),
/// using the `underlying` token's `transfer_from` method. It's typically used in wrapper implementations.
///
/// # Arguments
///
/// * `underlying` - The AccountId of the underlying token contract.
/// * `sender` - The AccountId of the sender who is depositing tokens.
/// * `contract` - The AccountId of this contract, which will receive the tokens.
/// * `value` - The amount of tokens to be deposited.
///
/// # Returns
///
/// A `Result<(), PSP22Error>` indicating the success or failure of the operation.
pub fn deposit(&mut self,
underlying: AccountId,
sender: AccountId,
contract: AccountId,
value: u128
) -> Result<(), PSP22Error> {
pub const TRANSFER_FROM_SELECTOR: [u8; 4] = [84, 179, 199, 110];

build_call::<DefaultEnvironment>()
.call(underlying)
.gas_limit(0)
.transferred_value(0)
.exec_input(
ExecutionInput::new(Selector::new(TRANSFER_FROM_SELECTOR))
.push_arg(sender)
.push_arg(contract)
.push_arg(value)
.push_arg(Vec::<u8>::new())
)
.returns::<Result<(), PSP22Error>>()
.invoke()
}

/// Withdraws a specified amount of tokens from this contract to a specified account.
///
/// This method transfers tokens from this contract to the `account` specified,
/// using the `underlying` token's `transfer` method. It's typically used in wrapper implementations.
///
/// # Arguments
///
/// * `underlying` - The AccountId of the underlying token contract.
/// * `account` - The AccountId where tokens will be withdrawn to.
/// * `value` - The amount of tokens to be withdrawn.
///
/// # Returns
///
/// A `Result<(), PSP22Error>` indicating the success or failure of the operation.
pub fn withdraw(&mut self,
underlying: AccountId,
account: AccountId,
value: u128
) -> Result<(), PSP22Error> {
pub const TRANSFER_SELECTOR: [u8; 4] = [219, 32, 249, 245];

build_call::<DefaultEnvironment>()
.call(underlying)
.gas_limit(0)
.transferred_value(0)
.exec_input(
ExecutionInput::new(Selector::new(TRANSFER_SELECTOR))
.push_arg(account)
.push_arg(value)
.push_arg(Vec::<u8>::new())
)
.returns::<Result<(), PSP22Error>>()
.invoke()
}

}
9 changes: 9 additions & 0 deletions errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,12 @@ pub enum PSP22Error {
/// Returned if a safe transfer check failed [deprecated].
SafeTransferCheckFailed(String),
}

/// Errors related to ownership operations.
///
/// This enum is used for managing errors that occur in ownership-related
/// functionalities.
#[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)]
#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
pub enum OwnableError {
}
124 changes: 123 additions & 1 deletion traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use ink::{
};

use crate::errors::PSP22Error;
use crate::errors::OwnableError;

#[ink::trait_definition]
pub trait PSP22 {
Expand Down Expand Up @@ -153,6 +154,23 @@ pub trait PSP22Burnable {
/// Reverts with `InsufficientBalance` if the `value` exceeds the caller's balance.
#[ink(message)]
fn burn(&mut self, value: u128) -> Result<(), PSP22Error>;

/// Burns `value` tokens from the "account" account id. Spends allowances.
///
/// The selector for this message are
/// first 4 bytes of `blake2b_256("PSP22Burnable::burn_from")`
///
/// # Events
///
/// On success a `Transfer` event is emitted with `None` recipient.
///
/// No-op if `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 burn_from(&mut self, account: AccountId, value: u128) -> Result<(), PSP22Error>;
}

#[ink::trait_definition]
Expand All @@ -172,5 +190,109 @@ pub trait PSP22Mintable {
/// Reverts with `Custom (max supply exceeded)` if the total supply increased by
/// `value` exceeds maximal value of `u128` type.
#[ink(message)]
fn mint(&mut self, value: u128) -> Result<(), PSP22Error>;
fn mint(&mut self, to: AccountId, value: u128) -> Result<(), PSP22Error>;
}


/// Trait for pausing and unpausing token transfers.
///
/// This trait allows the contract owner to pause or unpause token transfers,
/// which can be useful in emergency situations or during maintenance.
#[ink::trait_definition]
pub trait PSP22Pausable {
/// Pauses all token transfers.
///
/// This method is used to temporarily halt all transfer operations.
///
/// # Returns
///
/// A `Result<(), PSP22Error>` indicating whether the operation was successful.
#[ink(message)]
fn pause(&mut self) -> Result<(), PSP22Error>;

/// Unpauses all token transfers.
///
/// This method re-enables token transfer operations.
///
/// # Returns
///
/// A `Result<(), PSP22Error>` indicating whether the operation was successful.
#[ink(message)]
fn unpause(&mut self) -> Result<(), PSP22Error>;
}

/// Trait for wrapping and unwrapping PSP22 tokens.
///
/// This trait provides methods for depositing and withdrawing tokens,
/// often used in implementations that wrap other token standards.
#[ink::trait_definition]
pub trait PSP22Wrapper {
/// Deposits tokens into the contract for a specified account.
///
/// This method allows a user to add tokens to the contract, which can be used
/// for various functionalities like staking or liquidity provision.
///
/// # Arguments
///
/// * `account` - The account for which the tokens will be deposited.
/// * `amount` - The amount of tokens to deposit.
///
/// # Returns
///
/// A `Result<(), PSP22Error>` indicating the success or failure of the operation.
#[ink(message)]
fn deposit_for(&mut self, account: AccountId, amount: u128) -> Result<(), PSP22Error>;

/// Withdraws tokens from the contract to a specified account.
///
/// This method allows users to withdraw their tokens from the contract.
///
/// # Arguments
///
/// * `account` - The account to which the tokens will be withdrawn.
/// * `amount` - The amount of tokens to withdraw.
///
/// # Returns
///
/// A `Result<(), PSP22Error>` indicating the success or failure of the operation.
#[ink(message)]
fn withdraw_to(&mut self, account: AccountId, amount: u128) -> Result<(), PSP22Error>;
}

/// Trait for ownership-related functionalities.
///
/// Provides methods for managing ownership of the contract, including
/// transferring and renouncing ownership.
#[ink::trait_definition]
pub trait Ownable {
/// Returns the address of the current owner.
///
/// # Returns
///
/// The `AccountId` of the current owner.
#[ink(message)]
fn owner(&self) -> Option<AccountId>;

/// Renounces ownership of the contract.
///
/// This method is used to permanently transfer control of the contract
/// away from the current owner, leaving it without an owner.
///
/// # Returns
///
/// A `Result<(), OwnableError>` indicating whether the operation was successful.
#[ink(message)]
fn renounce_ownership(&mut self) -> Result<(), OwnableError>;

/// Transfers ownership of the contract to a new account.
///
/// # Arguments
///
/// * `new_owner` - The `AccountId` of the new owner.
///
/// # Returns
///
/// A `Result<(), OwnableError>` indicating whether the operation was successful.
#[ink(message)]
fn transfer_ownership(&mut self, new_owner: Option<AccountId>) -> Result<(), OwnableError>;
}