How do I let a user transfer ERC1155 token from my contract address to his address?

safeTransferFrom(address(this), msg.sender, ProjectB, 1, "0x0");

I get this error: execution reverted: ERC1155: caller is not owner nor approved.

You should add a custom function users can call, and internally use _safeTransferFrom.

Hi @frangio , thanks for replying.
I am not understanding, can you please share any example code?
I am minting tokens in the constructor to address(this) and when the user call the buy function then transferring this token to the caller’s address.
I want this process like, in ERC20 we use to transfer().
with current functionality, I have to approve users every time.
Is this possible, that our contract itself can send tokens to msg.sender based on any condition?

   //user will buy share for ProjectA
    //user will send 100 API tokens to this address to by RS-NFT for ProjectA
    function buyRSNFTForProjectA() external {
    //checking balance Of AliAPIToken in user's account
    require(balanceOf(msg.sender,AliAPIToken) != 0, "Please buy API tokens first to buy RS-NFT");
    //transferring tokens from user aaccount to this contract address
     safeTransferFrom(msg.sender,address(this), AliAPIToken,100,"");
    //transfer RS-NFT to user
    safeTransferFrom(address(this), msg.sender, ProjectA, 1, "");
    
    }```

You’re using safeTransformFrom which is the public function. This function will require that msg.sender has permission to transfer these tokens, so the transfer you want to do will fail.

Instead, if you use the internal _safeTransferFrom function you can transfer without checking that msg.sender has permissions. You should use this one.

1 Like

@frangio thankyou so much.
I am not able to make this contract ERC1155 holder, it is already implementing IERC1155Receiver.
Not working with this.(ERC1155: transfer to non ERC1155Receiver implementer)
When I import ERC1155 holder, it gives me error.

execution reverted: ERC1155: transfer to non ERC1155Receiver implementer
Trx hash
Is there any way to make this contract holder?
I am using ^0.8, _safeTransferFrom is not available in older versions.

What error do you see?

TypeError: Derived contract must override function “supportsInterface”. Two or more base classes define function with same name and parameter types. → Task9.sol:10:1: | 10 | contract ALIAPIToken is ERC1155,ERC1155Holder,Ownable{ | ^ (Relevant source part starts here and spans across multiple lines). Note: Definition in “ERC1155”: → https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC1155/ERC1155.sol:41:5: | 41 | function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { | ^ (Relevant source part starts here and spans across multiple lines). Note: Definition in “ERC1155Receiver”: → https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC1155/utils/ERC1155Receiver.sol:15:5: | 15 | function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { | ^ (Relevant source part starts here and spans across multiple lines).

@frangio this is my code

// contracts/GameItems.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.0;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC1155/ERC1155.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC1155/utils/ERC1155Holder.sol";

contract ALIAPIToken is ERC1155,ERC1155Holder,Ownable{
    
    
    address private _token = 0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735; //dai address
    IERC20 private token;
    address panacloud;
    address dev;
    
    //tokens
    uint256 public constant AliAPIToken =0;
    uint256 public constant ProjectA = 1;
    uint256 public constant ProjectB = 2;
   
    //percentages
    uint256 public panaCloudPercentage = 5;
    uint256 public investorPercentage = 10;
 
    // minting two NFT's 
    constructor(address _panacloud,address _dev) ERC1155("") {
    panacloud = _panacloud;
    dev = _dev;
    token = IERC20(_token);
    //0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735
    _mint(address(this),ProjectA,1,"0x0"); //NFT
    _mint(address(this),ProjectB,2,"0x0"); //NFT
    setApprovalForAll(address(this), true);
    }
    //to check DAI token alallowance(for UI)
    function checkDaiAllowance() external view returns(uint daiAllowed){
        
    uint bal =  token.allowance(msg.sender,address(this));
        return bal;
    }
    
    //when this contract will receive any revenue eg.g dai token, it will percentages to panacloud, developer and Project Share holder.
    // he needs to call this ffunction.
    //we can automate this function by calling it in buyAPIToken function.
    //for now, as per my understanding I am doing this way
    function onDaiReceive(uint _daiAmount) external {
        
    // checing dai allowance is not equal to zero
    require(token.allowance(msg.sender,address(this)) != 0,"zero allowance, pleae approve DAI first to be used by this contract");
    
    address from = msg.sender;
    //transferring tokens from caller to this contract address
    require(token.transferFrom(from, address(this), _daiAmount)== true,"error");   
    
    //transferring tokens to API developer by getting percentage
    uint investorP = (_daiAmount*investorPercentage)/100;
    token.transfer(dev, investorP);
    
    //transferring token percentage to panacloud 
    uint panacloudP = (_daiAmount*panaCloudPercentage)/100;
    token.transfer(panacloud, panacloudP);
    
    //transfer tokens to API developer
    require(token.transfer(owner(), token.balanceOf(address(this))),"Fialed");
        
    }
    
    //user can buy AliAPIToken that is currency to to buy RS-NFT for differet projects.
    // he needs to set allowance first
    // _amount wil be amout of DAI tokens
    function buyAPIToken(uint _amount) external{
    //checking allowance
    require(token.allowance(msg.sender,address(this)) != 0,"zero allowance, pleae approve DAI first to be used by this contract");
    
    address from = msg.sender;
    //transferring DAI tokens from user to this address.
    // it is different than onDaiReceive
    require(token.transferFrom(from, address(this), _amount)== true,"error");
    //minting AliAPITokens to user
    _mint(msg.sender, AliAPIToken, _amount * 100, "");
    
}
    
    //user will buy share for ProjectA
    //user will send 100 API tokens to this address to by RS-NFT for ProjectA
    function buyRSNFTForProjectA() external {
    //checking balance Of AliAPIToken in user's account
    require(balanceOf(msg.sender,AliAPIToken) != 0, "Please buy API tokens first to buy RS-NFT");
    //transferring tokens from user aaccount to this contract address
    safeTransferFrom(msg.sender,address(this), AliAPIToken,100,"");
    //transfer RS-NFT to user
    _safeTransferFrom(address(this), msg.sender, ProjectA, 1, "");
    
    }

    
    //user will buy share for ProjectB
    //user will send 500 API tokens to this address to by RS-NFT for ProjectA
    function buyRSNFTForProjectB() external {
    //checking balance Of AliAPIToken in user's account
    require(balanceOf(msg.sender,AliAPIToken) != 0, "Please buy API tokens first to buy RS-NFT");
    
    //transferring tokens from user aaccount to this contract address
    safeTransferFrom(msg.sender,address(this), AliAPIToken,500,"");
    //transfer RS-NFT to user
    _safeTransferFrom(address(this), msg.sender, ProjectB, 1, "0x0");
    }

}

The error message says "Derived contract must override function supportsInterface".

You need to define this function and call super.supportsInterface in it.

    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155, ERC1155Receiver) returns (bool) {
        return super.supportsInterface(interfaceId);
    }