-
Notifications
You must be signed in to change notification settings - Fork 2
Open
Labels
Description
I built an ERC-20 fungible token. Token transfers work perfectly in Remix and also show in Metamask browser extension, but token transfer directly from metamask (send button) does not work.

if I push the send button, the transaction eventually fails (498 CMPN fail). The succesful send (1500 CMPN) was from Remix by calling the transfer function.
To reproduce it, you can deploy the following smart contract on Remix. The owner/deployer can mint new tokens with mintTokens(address destination_account, uint tokens_amount). Then you can try sending the minted tokens to a different account with Metamask browser extension.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract CharityToken is ERC20 {
address public caller;
address public authority;
mapping(address => bool) public frozen;
event Frozen(address account);
event Unfrozen(address account);
error Unauthorized();
modifier onlyAuthorizedCaller {
if (msg.sender != caller) {
revert Unauthorized();
}
_;
}
modifier onlyAuthority {
if (msg.sender != authority) {
revert Unauthorized();
}
_;
}
constructor(address _authority) ERC20("Compassion", "CMPN") {
caller = msg.sender;
authority = _authority;
}
function mintTokens(address account, uint tokens) external onlyAuthorizedCaller {
_mint(account, tokens);
}
function burnShopTokens(address shop) external onlyAuthorizedCaller {
uint balance = balanceOf(shop);
_burn(shop, balance);
}
function changeCaller(address new_caller) external onlyAuthority {
caller = new_caller;
}
function freeze(address account) external onlyAuthority {
frozen[account] = true;
emit Frozen(account);
}
function unfreeze(address account) external onlyAuthority {
frozen[account] = false;
emit Unfrozen(account);
}
function is_frozen(address account) public view returns (bool) {
return frozen[account];
}
function transfer(address to, uint256 value) override public returns (bool) {
address owner = _msgSender();
if (is_frozen(owner)) {
revert Unauthorized();
}
_transfer(owner, to, value);
return true;
}
function transferFrom(address from, address to, uint256 value) override public returns (bool) {
address spender = _msgSender();
if (is_frozen(spender) || is_frozen(from)) {
revert Unauthorized();
}
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
function decimals() override public pure returns (uint8) {
return 0;
}
}