1

Below is my lib.rs file for the token contract and it uses the Cardinal Cryptography PSP22 sample at https://github.com/Cardinal-Cryptography/PSP22

I am trying to implement swap for the transfer taxes to native tokens, to no avail!

#![cfg_attr(not(feature = "std"), no_std, no_main)]

#[cfg(feature = "contract")]
#[ink::contract]
mod token {
    use psp22::{PSP22Data, PSP22Error, PSP22Event, PSP22Metadata, PSP22};
    use psp22::PSP22Error::Custom;
    use ink::prelude::{string::String, vec::Vec};

    use ink::{
        env::{
            call::{build_call, ExecutionInput, Selector},
            DefaultEnvironment
        }
    };

    #[ink(storage)]
    pub struct Token {
        data: PSP22Data,
        name: Option<String>,
        symbol: Option<String>,
        decimals: u8,
        owner: Option<AccountId>,
        reentrancy_lock: bool,
        trading: bool,
        pool_address: Option<AccountId>
    }

    impl Token {
        #[ink(constructor)]
        pub fn new(
            name: Option<String>,
            symbol: Option<String>,
            decimals: u8,
            total_supply: Balance
        ) -> Self {
            let owner = Self::env().caller();
            Self {
                data: PSP22Data::new(total_supply, owner),
                name,
                symbol,
                decimals,
                owner: Some(owner),
                reentrancy_lock: false,
                trading: false,
                pool_address: None
            }
        }

        fn emit_events(&self, events: Vec<PSP22Event>) {
            for event in events {
                match event {
                    PSP22Event::Transfer { from, to, value } => {
                        self.env().emit_event(Transfer { from, to, value })
                    }
                    PSP22Event::Approval {
                        owner,
                        spender,
                        amount,
                    } => self.env().emit_event(Approval {
                        owner,
                        spender,
                        amount,
                    }),
                }
            }
        }

        #[ink(message)]
        pub fn enable_trading(&mut self, pool_address: AccountId) -> Result<(), PSP22Error> {
            if self.env().caller() != self.owner.unwrap() {
                return Err(Custom(String::from("OnlyOwnerAllowed")));
            }
            self.pool_address = Some(pool_address);
            self.trading = true;
            Ok(())
        }

        #[inline]
        pub fn distribute_fees(&mut self) -> Result<(), PSP22Error> {

            let _ = ink::env::CallFlags::default().set_allow_reentry(true);

            if self.reentrancy_lock == true {
                return Ok(()); // Do not act if there is a reentry
            }

            self.reentrancy_lock = true;

            let amount = self.data.balance_of(self.env().account_id());
            
            if amount > 0 {
                self.swap_for_azero(amount)?;
            }

            self.reentrancy_lock = false;

            Ok(())

        }

        #[inline]
        pub fn swap_for_azero(&mut self, amount: Balance) -> Result<(), PSP22Error> {

            let pool_address = self.pool_address.unwrap();

            let azero_out = build_call::<DefaultEnvironment>()
            .call(pool_address)
            .exec_input(ExecutionInput::new(Selector::new(ink::selector_bytes!(
                "get_a0_amount_out_without_deduction"
            ))).push_arg(amount))
            .returns::<Balance>()
            .try_invoke().unwrap().unwrap();

            self.data.approve(self.env().account_id(), pool_address, amount)?;

            if build_call::<DefaultEnvironment>()
            .call(pool_address)
            .exec_input(ExecutionInput::new(Selector::new(ink::selector_bytes!(
                "swap_psp22"
            )))
            
            .push_arg(amount)
            .push_arg(azero_out)
            .push_arg(100 * 10u128.pow(12)))

            .returns::<()>()
            .try_invoke().is_err() {
                return Err(Custom(String::from("PSP22 Swap Failed")));
            }

            Ok(())

        }

    }

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

    #[ink(event)]
    pub struct Transfer {
        #[ink(topic)]
        from: Option<AccountId>,
        #[ink(topic)]
        to: Option<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.balance_of(owner)
        }

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

        #[ink(message)]
        fn transfer(
            &mut self,
            to: AccountId,
            value: u128,
            _data: Vec<u8>,
        ) -> Result<(), PSP22Error> {
            if self.env().caller() == self.env().account_id() || self.trading == false {
                let events = self.data.transfer(self.env().caller(), to, value)?;
                self.emit_events(events);
            }
            else {
                let fee = (value * 3) / 100;
                let amt = value - fee;

                let _ = self.data.transfer(self.env().caller(), self.env().account_id(), fee)?;

                if self.env().caller() != self.pool_address.unwrap() {
                    self.distribute_fees()?;
                }

                let events = self.data.transfer(self.env().caller(), to, amt)?;
                self.emit_events(events);
            }
            Ok(())
        }

        #[ink(message)]
        fn transfer_from(
            &mut self,
            from: AccountId,
            to: AccountId,
            value: u128,
            _data: Vec<u8>,
        ) -> Result<(), PSP22Error> {

            if from == self.env().account_id() || self.trading == false {
                let events = self
                .data
                .transfer_from(self.env().caller(), from, to, value)?;
                self.emit_events(events);
            }
            else {
                let fee = (value * 3) / 100;
                let amt = value - fee;

                let _ = self
                .data
                .transfer_from(self.env().caller(), from, self.env().account_id(), fee)?;

                if from != self.pool_address.unwrap() {
                    self.distribute_fees()?;
                }

                let events = self
                .data
                .transfer_from(self.env().caller(), from, to, amt)?;
                self.emit_events(events);
            }


            let events = self
                .data
                .transfer_from(self.env().caller(), from, to, value)?;
            self.emit_events(events);
            Ok(())
        }

        #[ink(message)]
        fn approve(&mut self, spender: AccountId, value: u128) -> Result<(), PSP22Error> {
            let events = self.data.approve(self.env().caller(), spender, value)?;
            self.emit_events(events);
            Ok(())
        }

        #[ink(message)]
        fn increase_allowance(
            &mut self,
            spender: AccountId,
            delta_value: u128,
        ) -> Result<(), PSP22Error> {
            let events = self
                .data
                .increase_allowance(self.env().caller(), spender, delta_value)?;
            self.emit_events(events);
            Ok(())
        }

        #[ink(message)]
        fn decrease_allowance(
            &mut self,
            spender: AccountId,
            delta_value: u128,
        ) -> Result<(), PSP22Error> {
            let events = self
                .data
                .decrease_allowance(self.env().caller(), spender, delta_value)?;
            self.emit_events(events);
            Ok(())
        }
    }

    impl PSP22Metadata for Token {
        #[ink(message)]
        fn token_name(&self) -> Option<String> {
            self.name.clone()
        }
        #[ink(message)]
        fn token_symbol(&self) -> Option<String> {
            self.symbol.clone()
        }
        #[ink(message)]
        fn token_decimals(&self) -> u8 {
            self.decimals
        }
    }
    
}

When I enable trading, the contract gets trapped in the transfer_from and transfer methods respectively.

How do I fix the problem? Can anyone spot out the issue? Is there something wrong somewhere?

You can use `cargo +nightly contract build --release --features "contract" to build (compile) the code.

Also, below is the Cargo.toml file content:

[package]
name = "psp22"
version = "0.2.1"
edition = "2021"
authors = ["Edinyanga Ottoho"]

[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 }

psp22 = { git = "https://github.com/Cardinal-Cryptography/PSP22.git", default-features = false }

[lib]
path = "lib.rs"

[features]
contract = []
default = ["std"]
std = [
    "ink/std",
    "scale/std",
    "scale-info/std",
    "psp22/std"
]

ink-as-dependency = []

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.