Search code examples
tokenethereumblockchainsoliditysmartcontracts

How i make my smart-contract interact with my token?


I'm trying to develop a smart-contract where people can publish and get paid by it, i want the person get paid in the token of the platform not in eth. Without using the token the contract works ok, but when i try adding the contract doesn't works.

Thats the Token code:

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

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/extensions/ERC20Capped.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/extensions/ERC20Burnable.sol";

contract NewsToken is ERC20Capped, ERC20Burnable {
    address payable public owner;
    uint256 public blockReward;
    mapping(address => bool) public validators;

    constructor(uint256 cap, uint256 reward) ERC20("News Token", "NWT") ERC20Capped(cap * (10 ** decimals())) {
        owner = payable(msg.sender);
        _mint(owner, 70000000 * (10 ** decimals()));
        blockReward = reward * (10 ** decimals());
    }

    function _mint(address account, uint256 amount) internal virtual override(ERC20Capped, ERC20) {
        require(ERC20.totalSupply() + amount <= cap(), "ERC20Capped: cap exceeded");
        super._mint(account, amount);
    }

    function _mintMinerReward() internal {
        _mint(block.coinbase, blockReward);
    }

    function _beforeTokenTransfer(address from, address to, uint256 value) internal virtual override {
        if(from != address(0) && to != block.coinbase && block.coinbase != address(0)) {
            _mintMinerReward();
        }
        super._beforeTokenTransfer(from, to, value);
    }

    function setBlockReward(uint256 reward) public onlyOwner {
        blockReward = reward * (10 ** decimals());
    }

    function destroy() public onlyOwner {
        selfdestruct(owner);
    }

    function becomeValidator() public {
        require(balanceOf(msg.sender)>=1000000 * (10 ** decimals()), "You need at least 1.000.000 tokens to become a validator");
        validators[msg.sender] = true;
    }

    function removeValidator() public {
        require(validators[msg.sender], "You are not a validator");
        validators[msg.sender] = false;
    }

    function checkValidator() public view returns (bool){
        return validators[msg.sender];
    }

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

    function callApprove(address _sender,address _writer, uint256 _amount) public {
        _sender.approve(_writer, _amount);

    }

}

Thats the Contract code:

//contracts/Web3News.sol
//SPDX-License-Identifier: MIT

import "./paymentManager.sol";
import "./NewsToken.sol";



pragma solidity ^0.8.17;

contract Web3News{
    address public writer;
    string public title;
    string public topics;
    string private subject;
    string private Autentic = "O artigo e verdadeiro";
    string private Fake = "O artigo e Falso";
    uint public minimumPayment;
    uint public itsAutentic;
    uint public itsFake;
    mapping(address => bool) public buyers;
  

    //Importa o contrato do NewsToken e do PaymentManager
    NewsToken public newsToken;
    //PaymentManager public paymentManager;


    event LogSecretAccess(address indexed sender);

    constructor(address _newsTokenAddr, string memory _title, string memory _topics, string memory _subject, uint _minimumPayment){
        writer = msg.sender;
        title = _title;
        topics = _topics;
        subject = _subject;
        minimumPayment = _minimumPayment;
        newsToken = NewsToken(_newsTokenAddr);
        //paymentManager = PaymentManager(_paymentManagerAddr);
    }

    //Da acesso do conteudo do artigo para quem pagar
    //function getAccessToArticle() public payable{
        //Verifica no contrato do NewsToken se o usuario tem saldo suficiente para pagar a taxa minima
      //  require(newsToken.balanceOf(msg.sender) >= minimumPayment, "Not enough tokens.");
        //Faz o pagamento do artigo para o contrato do PaymentManager que manda o pagamento ao criador do artigo
        //newsToken.approve(address(this), minimumPayment);
        //require(newsToken.allowance(msg.sender, address(this)) >= minimumPayment, "You have not approved the contract to transfer the tokens");
       // newsToken.transferFrom(msg.sender, writer, minimumPayment);
       // buyers[msg.sender] = true;
        //paymentManager.payForNews(address(this), minimumPayment);
    //}

    function getAccessToArticle1() public payable {
        require(newsToken.balanceOf(msg.sender) >= minimumPayment, "Not enough tokens");
        newsToken.approve(address(this), minimumPayment);
        //chamar uma funcao que transfere os fundos do msg.sender pra o contrato?
        newsToken.transferFrom(msg.sender, writer, minimumPayment);
        //newsToken.transfer(tx.origin, minimumPayment);
        buyers[msg.sender] = true;
    }
    
    //function getAccessToArticle() public payable {
      //  require(newsToken.balanceOf(msg.sender) >= minimumPayment, "Not enough tokens.");
        //address tokenContractAddress = address(newsToken);
        //bytes memory data = abi.encodeWithSignature("transfer(address,uint256)", address(writer), minimumPayment);
        //(bool success, bytes memory returnedData) = tokenContractAddress.call(data);
        //require(success, "The call to the transfer function was not successful.");
        //buyers[msg.sender] = true;
    //}


    
    //Puxa o conteudo do artigo para o usuario caso o mesmo tenha pago a taxa minima para acessar o artigo
    function readArticle() public returns (string memory) {
        //Verifica no contrato do PaymentManager se o usuario se encontra na lista de compradores
        require(buyers[msg.sender], "This address haven't purchased the article");
        emit LogSecretAccess(msg.sender);
        return subject;
    }

    //Funcao para votar como fakenews
    function fakenews(bool _itsAutentic) public {
        require(buyers[msg.sender], "This address haven't purchased the article, so it can't vote");
        if (_itsAutentic) {
            itsAutentic = itsAutentic + 1;
        } else {
            itsFake = itsFake + 1;
        }
    }

    //Funcao para julgar se e ou nao fakenews. Deve ser ativada somente por um autenticador/delegado
    function judgement() public view returns (string memory) {
        //Verifica se o endereco que esta chamando a funcao e um autenticador na lista de autenticadores do NewsToken
        require(newsToken.checkValidator(), "This address is not a validator");
        if (itsAutentic > itsFake) {
            return Autentic; 
        } else {
            return Fake;
        }
    }
    
    //Funcao para punir quem autenticar a noticia de forma erronea

}

I know that the problem is: when calling the transfer method on the token the address that is calling the function is the address of the contract and not the msg.sender, i had try the call(), the delegatecall(), and other methods. It's not clear to me how can i sove that, hopping some one can help me here...


Solution

  • After some time I discovered what is the problem, to make the token transaction I need to approve the contract address on the token contract so I can call the .transferFrom in the other contract!

    On the token contract

    Aprove(contractAddress,amount);
    

    On the contract ir self

    token.tranferFrom(adress1, adress2, amount);