1

I wrote a smart contract, implementing a psp34 token (docs). Inside the smart contract, it is no problem using the methods provided by openbrush. However, when I deploy it on chain and want to call a method (like for example owner_of), using the pokadot{.js} api, I run into the following problem:

When looking at the metadata of my contract, a typical method looks like this:

{
      "args": [
        {
          "label": "id",
          "type": {
            "displayName": [
              "Vec"
            ],
            "type": 7
          }
        }
      ],
      "docs": [
        " Returns the owner of a token."
      ],
      "label": "owner_of",
      "mutates": false,
      "payable": false,
      "returnType": {
        "displayName": [
          "Option"
        ],
        "type": 24
      },
      "selector": "..."
    },

But a method from the openbrush looks like this:

{
      "args": [
        {
          "label": "id",
          "type": {
            "displayName": [
              "psp34_external",
              "OwnerOfInput1"
            ],
            "type": 1
          }
        }
      ],
      "docs": [
        " Returns the owner of the token if any."
      ],
      "label": "PSP34::owner_of",
      "mutates": false,
      "payable": false,
      "returnType": {
        "displayName": [
          "psp34_external",
          "OwnerOfOutput"
        ],
        "type": 24
      },
      "selector": "..."
    }

From my understanding the polkadot api changes the label from 'owner_of' to 'ownerOf'. But what does it to 'PSP34::owner_of'?

I tried to call the original PSP34 owner_of method like this:

const { gasRequired, storageDeposit, result, output } = await contract.query.ownerOf(
    accountId,
    {
    gasLimit,
    storageDepositLimit,
    },
    id
)

But it does gives the error 'ownerOf is not a function'. My solution so far was to just implement a method in my contract which calls on the PSP34 owner_of method, and to then call this new method with the API.

Although this works, it strikes me as not pretty. Especially, since the original PSP34 owner_of method is still visible on chain.

My question now is: Is it possible to call the PSP34::owner_of method with the polkadot api? And if not, how can I overwrite the method so only the method in my contract is visible to the chain and I can call it with the polkadot api like before.

1 Answer 1

3

PSP34 in the rust level is a trait(interface) implemented by your contract. At the ABI level is a prefix or a namespace of the method that makes it unique. It allows supporting several methods with the same naming but with different prefixes.

// First
impl Contract {
    #[ink(message)]
    pub fn balance_of(&self, owner: AccountId) -> Balance { ... }
}

// Second
impl PSP22 for Contract {
    #[ink(message)]
    pub fn balance_of(&self, owner: AccountId) -> Balance { ... }
}

// Third
impl PSP34 for Contract {
    #[ink(message)]
    pub fn balance_of(&self, owner: AccountId) -> Balance { ... }
}

All those three implementations will generate different labels and selectors(selector is 4 bytes of the black2b hash of the label) for your methods:

  • First: "label": "balance_of", "selector": "0x0f755a56"
  • Second: "label": "PSP22::balance_of", "selector": "0x6568382f"
  • Third: "label": "PSP34::balance_of", "selector": "0xcde7e55f"

The polkadot-js can work with prefix and non-prefixed methods. It campelCase prefix and name of the method.

  • First: contract.query.balanceOf or contract.query["balanceOf"]
  • Second: contract.query["psp22::balanceOf"]
  • Third: contract.query["psp34::balanceOf"]

The same works for the tx namespace. Maybe it can be changed in the future after resolving issue.

It should solve your problem=) But I suggest you try typechain-polkadot for integration tests and frontend development. It will generate all classes based on the ABI of your contract, and you will know how to call each method.

2
  • I tried to follow your advice, but still get the 'not a function' error. I also tried to implement the method in 'impl PSP34 for Contract' but same problem. Neither in camelCase nor in label format.
    – rajohs
    Aug 15, 2022 at 19:29
  • You are right=D It was changed again... Right now it is psp22::balanceOf. I've updated the comment. Also, I added more documentation to typechain-polkadot, so it should be easy to use right now=) Aug 16, 2022 at 14:49

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.