0

Below is my solidity code. I am trying to send MATIC to the "receiverAddress". Everything looks fine. I have 2.3875 MATIC in my wallet and I'm inserting 87500000000000000 as sending MATIC value. But after the transaction completed no MATIC is dropping from my wallet and none is sent to the "receiverAddress". What is wrong in my function?

Here is the transaction details on Polygonscan Mumbai: https://mumbai.polygonscan.com/tx/0x2b67e379f3117fe5a05242339588a8113bd923fe40106e676db8199a64787f7a

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract MaticTransfer {
    address public constant receiverAddress = 0x7d55273b60BEc66895f547515256E092f31c61B8;
    address public owner;

    IERC20 public maticToken;

    constructor(address _maticTokenAddress) {
        owner = msg.sender;
        maticToken = IERC20(_maticTokenAddress);
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Only the contract owner can call this function");
        _;
    }

    function transferMatic(uint256 _amount) public  payable  {

        require(_amount > 0, "Amount should be greater than zero");

        uint256 balance = maticToken.balanceOf(address(this));
        require(balance <= _amount, "Insufficient balance in the contract");

        maticToken.transfer(receiverAddress, _amount);
    }

    function getContractBalance() external view returns (uint256) {
        return maticToken.balanceOf(address(this));
    }
}

Update:

When I entered the value at "1" it droped the MATIC from my wallet. I was trying to enter at "2". But it is not received from "receiverAddress". Where did that MATIC go? If it is on smartcontract how we can make this to send to the wallet?

enter image description here

1 Answer 1

0

Welcome!

Let's break this down a bit. I'll call 0x28362251e41186e518f1f2df2e4cb03f1690b6f0 "you", 0x94A8cF6ED56F6d3500f901bb911BBc6cA6CE88Aa "the contract", and 0x7d55273b60BEc66895f547515256E092f31c61B8 "the recipient.

  1. You have MATIC in your wallet.
  2. You want to send this to the recipient.
  3. To do so, you're calling the contract, which has a function that calls transfer on the MRC contract (0x...1010).

There are a couple of issues here. The first is that even if the call would be successful, you'd be transferring MATIC from the contract, not from you; the contract would be msg.sender on the call to transfer. In other words, transfer is a function which transfers from the account calling the transfer function (the msg.sender of the call to transfer). Here, the contract is calling transfer. You may be thinking of transferFrom, which allows a contract to initiate a transfer from someone else's account, provided that is has received approval to do so.

The other issue is specific to MATIC, but has roots in understanding the difference between a native asset and an ERC20. MATIC is the native asset of Mumbai and Polygon's POS chain, not an ERC20 contract. The 0x...1010 address helps give some ERC20 functionality to MATIC, but does not work exactly like an ERC20 contract. Here is the transfer function:

function transfer(address to, uint256 value) public payable returns (bool) {
    if (msg.value != value) {
        return false;
    }
    return _transferFrom(msg.sender, to, value);
}

As you may be able to tell, the function is designed to receive a native MATIC transfer, and simply returns false if the MATIC isn't sent with the call to transfer. As you/the contract didn't send any MATIC along with the call to transfer, the function would simply return false.

The reason for this is that unlike ERC20 tokens, there is not currently any way to "pull" a native asset from a different address the way that approvals and transferFrom do for ERC20s. (EIP-3074 provides a proposal that would allow something like this, but thus far no chain has implemented it afaik.) As a result, there is no way for the MRC contract to reach in and take the MATIC in order to send it, and it needs to be sent along with the call.

Lastly, when you used the value field on Remix instead of the transferMatic field, this included MATIC with your call to the transferMatic function, but the transferMatic function never passes along the MATIC it was sent. As a result, the MATIC left your wallet, and was sent to the contract, not the recipient.

I hope that clears things up!

3
  • Thank you for your detailed explanation. So I can not send any MATIC from myself to another wallet trough the contract. For that I need to create another way that I send MATIC to contract and the "receiver" should connect to cotract and "pull" the MATIC from contract. Is that correct?
    – nihilisama
    Commented Nov 2, 2023 at 18:10
  • You can in theory, but not this contract. You would need to send the MATIC that you want to transfer to the contract from the EOA, and then to have the contract send it along. This would mean adding value to the call to the function, and then using something like .transfer() or .call() in the contract. At that point, you wouldn't need to call 0x...1010 directly, tbh - you could send the MATIC directly to the recipient. To understand transferring native tokens more, try solidity-by-example.org/sending-ether. MATIC on Polygon works the same way as ETH on Ethereum wrt this. Commented Nov 3, 2023 at 12:37
  • Also, if the answer is helpful, please do upvote it and mark it as the answer (by clicking on the checkmark). Commented Nov 3, 2023 at 12:37

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.