0

I created a smart contract thanks to the documentation on tezos: https://tezos.com/developers/tutorials/nft-markeplace

I wanted to be able to test the transfer functionality of nft between users or from an admin to a user, here is my smart contract: https://legacy.smartpy.io/ide?cid=QmZV5uYwZE6j5CvMk7yufbbWAEdqtie4CtxvAcWbeyTXS4&k=12f8f7f6e9e6bcab06af

The problem occurs in the test for the transfer:

# Transfert d'un NFT
scenario.h1("Transfert d'un NFT")
marketplace.fa2_transfer(
    fa2=token_contract.address,
    from_=mark.address,
    to_=elon.address,
    token_id=0,
    amount=sp.nat(5_600_000)
).run()

I have an error message: Message: 'FA2_NOT_OPERATOR'

Here is my function:

@sp.entry_point
def fa2_transfer(self, fa2, from_, to_, token_id, amount):
    c = sp.contract(sp.TList(sp.TRecord(from_=sp.TAddress, txs=sp.TList(sp.TRecord(amount=sp.TNat, to_=sp.TAddress, token_id=sp.TNat).layout(("to_", ("token_id", "amount")))))), fa2, entry_point='transfer').open_some()
    sp.transfer(sp.list([sp.record(from_=from_, txs=sp.list([sp.record(amount=amount, to_=to_, token_id=token_id)]))]), sp.mutez(0), c)

And my full test:

@sp.add_test(name = "Non Fungible Token")
def test():
    scenario = sp.test_scenario()
    
    admin = sp.test_account("admin")
    mark = sp.test_account("user1")
    elon = sp.test_account("user2")

    token_contract = Token(
        admin=admin.address,
        metadata=sp.utils.metadata_of_url(
            "ipfs://QmW8jPMdBmFvsSEoLWPPhaozN6jGQFxxkwuMLtVFqEy6Fb"))
    scenario += token_contract

    scenario.h1("MarketPlace")
    marketplace = Marketplace(
        token_contract.address,
        sp.utils.metadata_of_url(
            "ipfs://QmW8jPMdBmFvsSEoLWPPhaozN6jGQFxxkwuMLtVFqEy6Fb"
        ), admin.address)
    scenario += marketplace

    marketplace.mint(
        amount=sp.tez(100),
        metadata=sp.pack(
            "ipfs://bafyreibwl5hhjgrat5l7cmjlv6ppwghm6ijygpz2xor2r6incfcxnl7y3e/metadata.json"
    )).run(sender=admin, valid=False, exception="FA2_NOT_ADMIN")
    token_contract.set_administrator(marketplace.address).run(sender=admin)

    
    scenario.h1("Mint admin")
    marketplace.mint(
        amount=sp.tez(100),
        metadata= sp.pack(
            "ipfs://bafyreibwl5hhjgrat5l7cmjlv6ppwghm6ijygpz2xor2r6incfcxnl7y3e/metadata.json"
        )).run(sender=admin)
    
    scenario.h1("Mint mark")
    marketplace.mint(amount=sp.mutez(5_600_000), metadata=sp.pack("123423")).run(sender=mark)
    

    scenario.h1("Collect")
    marketplace.collect(token_id=1).run(sender=elon, amount=sp.mutez(5_600_000))

    # Update admin
    scenario.h1("Update Admin")
    marketplace.update_admin(
        admin.address
    ).run(sender=admin)
    
    # Transfert d'un NFT
    scenario.h1("Transfert d'un NFT")
    marketplace.fa2_transfer(
        fa2=token_contract.address,
        from_=mark.address,
        to_=elon.address,
        token_id=0,
        amount=sp.nat(5_600_000)
    ).run()

    marketplace.collect_management_rewards(
        amount=sp.mutez(1000),
        address=admin.address
    ).run(sender=admin)

    

1 Answer 1

1

This error means that someone is trying to transfer tokens on behalf of someone else. In your case, the marketplace is trying to perform the transfer.

If you want to transfer on behalf of someone else, you have to call add_operator on the FA2 but I strongly discourage to do it in your particular case because then anyone will be able to transfer the token via fa2_transfer of the Marketplace without owning them.

Instead, I suggest you to call the transfer entrypoint on the FA2 directly.

Example on how to do it in test scenario:

token_contract.transfer([
    sp.record(
        from_=mark.address,
        txs=[sp.record(token_id=0, amount=5_600_000, to_=elon.address)]
)]).run(sender=mark)

In your code, you have to check that the from_ addresses is similar to the wallet address.

3
  • Thank you for your answer, it allows me to test the function. The problem is that I don't know how to call this method in my code. The other functions, I call them like this: const op = await contract.methods.mint(amount, bytes).send(); But I can't call this function like this: const operation = await contract.methods.transfer(transferParams).send({ sender: fromAddress });
    – TM Paolo
    Jun 8, 2023 at 20:59
  • I tried with this const operation = await contract.methods.transfer(transferParams).send({ sender: fromAddress }); But I have this error when paying the transaction: "string": "FA2_NOT_OPERATOR"
    – TM Paolo
    Jun 8, 2023 at 22:09
  • I edited my answer with a bit more context.
    – Jordan_tez
    Jun 14, 2023 at 14:16

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.