Calling another smart contract if it has a particular entrypoint

I have the following code

    stateful entrypoint safeTransferFromWithData(_from: address, _to: address, _tokenID: int, _data: string) =
        transferFrom(_from, _to, _tokenID)
        _invokeClassicNFTReceiver(_from, _to, _tokenID, _data)
    
    function _invokeClassicNFTReceiver(_from: address, _to: address, _tokenID: int, _data: string) : bool =
        if(Address.is_contract(_to))
            let c : ClassicNFTReceiver = Address.to_contract(_to)
            _callClassicNFTReceiverFunction(c, _from, _to, _tokenID, _data)
        else
            false

    function _callClassicNFTReceiverFunction(_contract: ClassicNFTReceiver, _from: address, _to: address, _tokenID: int, _data: string) : bool =
        switch(_contract.onClassicNFTReceived(_from, _to, _tokenID, _data, protected = true) : option(bool))
            None => false
            Some(val) => val

My goal in _invokeClassicNFTReceiver is to check whether the provided address is a contract, if so get the proper type and call the provided contract. It’s important that in case the contract is NOT implementing ClassicNFTReceiver that it will not fail, but simply return false instead.

For as far as I know Sophia has no try/catch system. So how can I accomplish this behavior? If there is a more efficient way to reach my goal then I’m open to that of course.

3 Likes

I am not 100% sure but I guess protected contract calls can be used to achieve what you need, see aesophia/sophia.md at master · aeternity/aesophia · GitHub

maybe @hanssv.chain or @radrow.chain can confirm or prove me wrong :sweat_smile:

Yes, exactly, in the latest update Sophia/FATE got protected calls: aesophia/sophia.md at master · aeternity/aesophia · GitHub

In short (not at a computer right now) this is try/catch for remote calls.

3 Likes

Good morning, teacher

1 Like

@zkvonsnarkenstein.chain can you already show your WIP state? you are working on the NFT standard, right? :slight_smile:

1 Like

I’m still struggling with this issue. I merged the two functions into one. It now looks like this:

stateful entrypoint safeTransferFromWithData(_from: address, _to: address, _tokenID: int, _data: string) =
        transferFrom(_from, _to, _tokenID)
        _invokeClassicNFTReceiver(_from, _to, _tokenID, _data)
    
    function _invokeClassicNFTReceiver(_from: address, _to: address, _tokenID: int, _data: string) : bool =
        if(Address.is_contract(_to))
            let c = Address.to_contract(_to)
            switch(c.onClassicNFTReceived(_from, _to, _tokenID, _data, protected = true) : option(bool))
                None => false
                Some(val) => val
        else
            false

The problem I’m having is that _to can be a normal address or a contract address. However, my test case fails when I provide a contract address to the entrypoint.

    it('Should do safe transfer to example contract', async () => {
        console.log(exampleContract.deployInfo.address);
        await contract.methods.mint(ownerKeypair.publicKey, 1);
        // await contract.methods.safeTransferFrom(ownerKeypair.publicKey, otherKeypair.publicKey, 1); // This works
        await contract.methods.safeTransferFrom(ownerKeypair.publicKey, exampleContract.deployInfo.address, 1); // This results in "Bad request"
    });

I’m trying to create an interface which is as close as possible to ERC-721, therefore I’m not using the contract type, but address as type of the argument. The function checks whether it’s a contract address or not.

What am I doing wrong or how to solve this?

I think here is the problem. when I am right according to short discussion with @nikitafuchs.chain you are providing the contract address ct_ instead of the account address of the contract ak_ as param to the function.

please check and replace ct_ with ak_ if this is the case. then it should hopefully work :smiley:

specifically talking about exampleContract.deployInfo.address

Usually, with bad request also comes some additional info, could you post it please ?

All it gives me is this:

    1) Should do safe transfer to example contract


  9 passing (2m)
  1 failing

  1) NFT Contract
       Should do safe transfer to example contract:
     Error: Bad Request
      at http (node_modules/swagger-client/lib/http.js:106:19)
      at runMicrotasks (<anonymous>)
      at processTicksAndRejections (internal/process/task_queues.js:93:5)

Yes, that did it. Now the test is passing as it should. Thanks!

2 Likes

really looking forward to that implementation :slight_smile:

please share the code with us as soon as you feel comfortable with it! :wink:

2 Likes