4

I created a Smart Contract, and i want that custom tokens interact with it.

Example:

pragma solidity >=0.7.0 <0.9.0;

contract PaymentInvoiceSplit {
    uint productPrice;

    constructor (uint defaultProductPrice) {
        owner = msg.sender;
        productPrice = defaultProductPrice;
    }

    function payInvoice (uint invoiceId) payable public {
      // Receive Amount
      // Split payment
      // Emit event
    }

    function kill () public onlyOwner() {
        selfdestruct(payable(owner));
    }
}

I'm using MetaMask:

  • Network: Smart Chain
  • Account Imported
  • Custom Token add as asset
  • I have funds on BNB for gas and Custom Token

MetaMask Account and Assets

Then i connected the front-end and try to call contract, but when the contract is called it is using ETH, but i want to use custom token instead:

window.onload = async () => {
    await window.ethereum.enable()

    web3 = new Web3(web3.currentProvider)
    const accounts = await ethereum.request({ method: 'eth_accounts' })

    const paymentInvoiceAbi = [
      {
        "inputs": [
          {
            "internalType": "uint256",
            "name": "invoiceId",
            "type": "uint256"
          }
        ],
        "name": "payInvoice",
        "outputs": [],
        "stateMutability": "payable",
        "type": "function"
      }
    ]

    const paymentInvoiceAddress = '0x'
    const paymentInvoiceContract = new web3.eth.Contract(paymentInvoiceAbi, paymentInvoiceAddress)

    const invoiceId = '123'
    const data = paymentInvoiceContract.methods.payInvoice(invoiceId).send({ from: accounts[0] })
  }

I can transfer funds from custom token to my smart contract, but this way i only can send amount and i can't call a contract method:

window.onload = async () => {
    await window.ethereum.enable()

    web3 = new Web3(web3.currentProvider)
    const accounts = await ethereum.request({ method: 'eth_accounts' })

    const tokenAbi = [
      {
        inputs: [
          {
            internalType: "address",
            name: "recipient",
            type: "address"
          },
          {
            internalType: "uint256",
            name: "amount",
            type: "uint256"
          }
        ],
        name: "transfer",
        outputs: [
          {
            internalType: "bool",
            name: "",
            type: "bool"
          }
        ],
        stateMutability: "nonpayable",
        type: "function"
      }
    ]

    const tokenAddress = '0xa'
    const paymentInvoiceAddress = '0xb'
    const tokenContract = new web3.eth.Contract(tokenAbi, tokenAddress)

    const value = web3.utils.toHex('3000000')
    const data = tokenContract.methods.transfer(paymentInvoiceAddress, value).send({ from: accounts[0] })
  }

There is any way to interact this two contract? Handle my smart contract using a custom token?

My objective is create a smart contract that receive funds from a custom token like BEP20 and handle it with a Smart Contract.

Thanks!

3
  • 1
    Could you share the relevant code? and also maybe reformulate? im kinda confused by your question
    – Foxxxey
    Oct 3, 2021 at 17:00
  • @Foxxxey i reformulated my question, can you help me? Thanks for you time. Oct 3, 2021 at 21:30
  • Not sure i understand but tokens != ether ether is not a contract. Tokens are contracts. Look at the erc20 standard transferFrom that will require approval. ether is refered to as msg.value. Token are refered to by the contract address. Look up IERC20 Oct 3, 2021 at 22:34

1 Answer 1

1

If you want the user to pay with tokens.

Your contract should look like this

pragma solidity >=0.7.0 <0.9.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
// npm install @openzeppelin-contracts required

contract PaymentInvoiceSplit {
    uint productPrice;

    constructor (uint defaultProductPrice) {
        owner = msg.sender;
        productPrice = defaultProductPrice;
    }

    function payInvoice (uint invoiceId, address token) payable public {

    IERC20 paymentToken = IERC20(token);
    uint256 amountToPay;

      // You must pull the amount
      // The amount must be approved by the account before the transfer

    require(paymentToken.allowance(msg.sender, address(this)) >= amountToPay,"Insuficient Allowance");
    require(paymentToken.transferFrom(msg.sender,address(this),amountToPay),"transfer Failed");

      // At this point you have the amountToPay in the contract
      // Do your stuff
      // Emit event
    }

}

In this example the caller would provide the address of the token he want's to pay with and the function would execute the transfer.

If you have special custom function in your token Contract you will have to interface them.

6
  • Hi, very thanks for you help! I think this is the best way to resolve it. I was trying a similar way, but in my testes i was getting balanceOf(msg.sender). I didin't know this allowance method, i'm getting a error about parameters, allowance needs two and is receiving zero. i think i need to pass the contract address and the spender, right? Ex: paymentToken.allowance(address(this), msg.sender) Oct 3, 2021 at 23:29
  • function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) The amount must be approved by the front end Oct 3, 2021 at 23:44
  • Now i'm getting the error: SafeMath: subtraction overflow I think is paymentToken.transferFrom(msg.sender, address(this), amountToPay). Do you have any suggestion? Thanks Oct 4, 2021 at 0:48
  • Maybe you should accept this as the answer and start a new question. Oct 4, 2021 at 0:55
  • 1
    Ok, Thanks for your time and help. Oct 4, 2021 at 1:02

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.