hello I'm trying to user a method from the smart contract and transfer token between different address but I got this error this is a link for the transaction
Error:
Warning! Error encountered during contract execution [execution reverted]
this is the code of the function of the contract :
function sendTokensFromCustomerToRetailer(address retailer, address customer, uint256 tokens) public onlyOwner {
increaseAllowance(customer, tokens * 10 ** uint256(decimals()));
transferFrom(customer, retailer, tokens * 10 ** uint256(decimals()));
updateRewardableBalancePerAddress(customer);
updateRewardableBalancePerAddress(retailer);
}
ERC20Upgradeable code:
contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, _allowances[owner][spender] + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = _allowances[owner][spender];
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[to] += amount;
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
smart contract code :
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
//pragma experimental ABIEncoderV2;
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
contract FidelityImplementationContract is OwnableUpgradeable, ERC20Upgradeable {
using SafeMathUpgradeable for uint256;
// *-*-*-*-*-*-*_Attibutes_*-*-*-*-*-*-*
// *-*-*-*-*-*-*_Constructor_*-*-*-*-*-*-*
// struct EchelonReward is used to build rewards echelons
struct EchelonReward {
uint256 echelonMaxValue;
uint256 percentage;
}
// stakeholders array
address[] internal stakeholders;
// minimum balance value since the last rewards distribution
mapping(address => uint256) internal rewardableBalance;
// timestamp to store when the next reward distribution will be possible
uint256 internal nextRewardsAvailableTime;
// duration between each reward distribution
uint256 internal rewardsDuration;
// reward percentage by tokens
EchelonReward[] internal rewardsPercentageByTokens;
// *-*-*-*-*-*-*_Constructor_*-*-*-*-*-*-*
function init(uint256 initialTokens) initializer public {
// SET THE OWNER HERE
__Ownable_init();
__ERC20_init("FidelityToken", "FT");
_mint(msg.sender, initialTokens * 10 ** uint256(decimals()));
fillRewardsPercentageByTokensOnStart();
nextRewardsAvailableTime = block.timestamp.add(rewardsDuration);
rewardsDuration = 2 minutes;
}
// *-*-*-*-*-*-*_Stakeholders_*-*-*-*-*-*-*
/**
* @notice A method to check if an address is a stakeholder.
* @param _address The address to verify.
* @return bool, uint256 Whether the address is a stakeholder,
* and if so its position in the stakeholders array.
*/
function isStakeholder(address _address)
public
onlyOwner
view
returns(bool, uint256)
{
for (uint256 s = 0; s < stakeholders.length; s += 1){
if (_address == stakeholders[s]) return (true, s);
}
return (false, 0);
}
/**
* @notice A method to add a stakeholder.
* @param _stakeholder The stakeholder to add.
*/
function addStakeholder(address _stakeholder)
public
onlyOwner
{
(bool _isStakeholder, ) = isStakeholder(_stakeholder);
if(!_isStakeholder) {
stakeholders.push(_stakeholder);
rewardableBalance[_stakeholder] = 0;
}
}
/**
* @notice A method to remove a stakeholder.
* @param _stakeholder The stakeholder to remove.
*/
function removeStakeholder(address _stakeholder)
public
onlyOwner
{
(bool _isStakeholder, uint256 s) = isStakeholder(_stakeholder);
if(_isStakeholder){
stakeholders[s] = stakeholders[stakeholders.length - 1];
stakeholders.pop();
rewardableBalance[_stakeholder] = 0;
}
}
// *-*-*-*-*-*-*_Rewards_*-*-*-*-*-*-*
/**
* @notice A simple method that calculates the rewards of the given stakeholder.
* @param _stakeholder The stakeholder to calculate rewards for.
*/
function calculateReward(address _stakeholder)
public
onlyOwner
view
returns(uint256)
{
return getRewardableBalanceByStakeholder(_stakeholder) * getRewardPercentage(_stakeholder) / 100;
}
/**
* @notice A method to get the rewardable balance of the given stakeholder.
* @param _stakeholder The stakeholder.
* @return The amount of the rewardable tokens of the given stakeholder
*/
function getRewardableBalanceByStakeholder(address _stakeholder)
public
onlyOwner
view
returns(uint256)
{
return rewardableBalance[_stakeholder];
}
/**
* @notice A method to get the reward percentage by balance.
* @param _stakeholder The stakeholder.
* @return The reward percentage according to the stakeholder's balance
*/
function getRewardPercentage(address _stakeholder)
public
onlyOwner
view
returns(uint256)
{
if (0 != rewardsPercentageByTokens.length) {
for (uint index = rewardsPercentageByTokens.length; index > 0; index--) {
if (rewardableBalance[_stakeholder] >= rewardsPercentageByTokens[index - 1].echelonMaxValue) {
return rewardsPercentageByTokens[index - 1].percentage;
}
}
}
return 0;
}
/**
* @notice A method to get the reward percentage by balance.
* @return The reward percentage according to the stakeholder's balance
*/
function getRewardsPercentageByTokens() public onlyOwner view returns (EchelonReward[] memory) {
return rewardsPercentageByTokens;
}
/**
* @notice A method to distribute rewards to all stakeholders.
*/
function distributeRewards()
public
onlyOwner
{
if (block.timestamp >= nextRewardsAvailableTime) {
for (uint256 s = 0; s < stakeholders.length; s += 1){
address stakeholder = stakeholders[s];
updateRewardableBalancePerAddress(stakeholder);
uint256 reward = calculateReward(stakeholder);
increaseAllowance(owner(), reward);
transferFrom(owner(), stakeholder, reward);
rewardableBalance[stakeholder] = balanceOf(stakeholder);
}
nextRewardsAvailableTime = block.timestamp.add(rewardsDuration);
}
}
/**
* @notice A method to update the rewards percentage echlons.
* @param newEchlonArray The new rewards echlons.
*/
function updateRewardsPercentageByTokens(EchelonReward[] memory newEchlonArray) public onlyOwner {
if (0 != newEchlonArray.length) {
delete rewardsPercentageByTokens;
for (uint index = 0; index < newEchlonArray.length; index++) {
EchelonReward memory echelon;
echelon.echelonMaxValue = newEchlonArray[index].echelonMaxValue * 10 ** uint256(decimals());
echelon.percentage = newEchlonArray[index].percentage;
rewardsPercentageByTokens[index] = echelon;
}
}
}
/**
* @notice A method to initialize the reward percntages.
*/
function fillRewardsPercentageByTokensOnStart() private onlyOwner {
rewardsPercentageByTokens.push(EchelonReward(
{
echelonMaxValue : 100 * 10 ** uint256(decimals()),
percentage : 1
}));
rewardsPercentageByTokens.push(EchelonReward(
{
echelonMaxValue : 500 * 10 ** uint256(decimals()),
percentage : 2
}));
rewardsPercentageByTokens.push(EchelonReward(
{
echelonMaxValue : 1000 * 10 ** uint256(decimals()),
percentage : 3
}));
rewardsPercentageByTokens.push(EchelonReward(
{
echelonMaxValue : 10000 * 10 ** uint256(decimals()),
percentage : 4
}));
rewardsPercentageByTokens.push(EchelonReward(
{
echelonMaxValue : 50000 * 10 ** uint256(decimals()),
percentage : 5
}));
}
/**
* @notice A method to update the rewardable balance for the given stakeholder.
* @param _stakeholder The stakeholder.
*/
function updateRewardableBalancePerAddress(address _stakeholder) public onlyOwner {
if (balanceOf(_stakeholder) < rewardableBalance[_stakeholder]) {
rewardableBalance[_stakeholder] = balanceOf(_stakeholder);
}
}
/**
* @notice A method to update the rewardable balance for all the stakeholders.
*/
function updateRewardableBalances() public onlyOwner {
for (uint index = 0; index < stakeholders.length; index++) {
updateRewardableBalancePerAddress(stakeholders[index]);
}
}
// *-*-*-*-*-*-*_Transactions_*-*-*-*-*-*-*
/**
* @notice A method to send tokens from the retailer to the customer.
* @param retailer The retailer address.
* @param customer The customer address.
* @param tokens The amount of tokens to send.
*/
function sendTokensFromRetailerToCustomer(address retailer, address customer, uint256 tokens) public onlyOwner {
increaseAllowance(retailer, tokens * 10 ** uint256(decimals()));
transferFrom(retailer, customer, tokens * 10 ** uint256(decimals()));
updateRewardableBalancePerAddress(customer);
updateRewardableBalancePerAddress(retailer);
}
/**
* @notice A method to send tokens from the customer to the retailer.
* @param retailer The retailer address.
* @param customer The customer address.
* @param tokens The amount of tokens to send.
*/
function sendTokensFromCustomerToRetailer(address retailer, address customer, uint256 tokens) public onlyOwner {
increaseAllowance(customer, tokens * 10 ** uint256(decimals()));
transferFrom(customer, retailer, tokens * 10 ** uint256(decimals()));
updateRewardableBalancePerAddress(customer);
updateRewardableBalancePerAddress(retailer);
}
/**
* @notice A method to enable customers to send tokens from one retailer to another.
* @param retailerSource The retailer source address.
* @param walletSource The customer address in the source retailer.
* @param walletDestination The customer address in the target retailer.
* @param tokensToSend The amount of tokens to send.
* @param feesForFidelityPercent The percentage of transaction fees for Fidelity.
* @param feesForRetailerSourcePercent The percentage of transaction fees for the source retailer.
*/
function tansfertFromRetailerToAnother(address retailerSource, address walletSource, address walletDestination, uint256 tokensToSend,
uint256 feesForFidelityPercent, uint256 feesForRetailerSourcePercent) public onlyOwner {
uint256 feesForFidelity = ((tokensToSend * feesForFidelityPercent) / 100) * 10 ** uint256(decimals());
uint256 feesForRetailerSource = ((tokensToSend * feesForRetailerSourcePercent) / 100) * 10 ** uint256(decimals());
increaseAllowance(walletSource, (tokensToSend * 10 ** uint256(decimals())) - feesForFidelity - feesForRetailerSource);
transferFrom(walletSource, walletDestination, (tokensToSend * 10 ** uint256(decimals())) - feesForFidelity - feesForRetailerSource);
increaseAllowance(walletSource, feesForRetailerSource);
transferFrom(walletSource, retailerSource, feesForRetailerSource);
increaseAllowance(walletSource, feesForFidelity);
transferFrom(walletSource, owner(), feesForFidelity);
updateRewardableBalancePerAddress(retailerSource);
updateRewardableBalancePerAddress(walletSource);
updateRewardableBalancePerAddress(walletDestination);
updateRewardableBalancePerAddress(owner());
}
/**
* @notice A method to mint extra tokens.
* @param tokens The amount of tokens to mint.
*/
function mintExtraTokens(uint256 tokens) public onlyOwner {
_mint(owner(), tokens * 10 ** uint256(decimals()));
}
/**
* @notice A method to burn tokens.
* @param tokens The amount of tokens to burn.
*/
function burnTokens(uint256 tokens) public onlyOwner {
_burn(owner(), tokens * 10 ** uint256(decimals()));
}
/**
* @notice A method to get the formatted balance of the given stakeholder.
* @param _stakeholder The stakeholder.
* @return The formatted balance of the given stakeholder
*/
function getFormattedBalance(address _stakeholder)
public
view
returns(uint256)
{
return balanceOf(_stakeholder) / 10 ** uint256(decimals());
}
}
the problem happen when I try to send token with the function sendTokensFromCustomerToRetailer() , when I use my address which is the address of the owner of the smart contract as a customer the transaction success , but when I use an other address as the address of the customer the transaction fail I mean only the transaction happen from my address to another I can't for example make transaction from another address to my address they always fail
here the transaction fail when I use an other address as customer address (not the address of the owner ):
this is a link for the transaction that fail : link
link for successful transaction : link