I have my contract deployed on the testnet and I am trying to call (mint-nft) which has no arguments, but it does have a require-capability ACCOUNT_GUARD. I am getting error as follows:
Error from (api.testnet.chainweb.com): : Failure: require-capability: not granted:
(free.slightly-less-shitty-nft-project.ACCOUNT_GUARD "k:ab7cef70e1d91a138b8f65d26d6917ffcb852b84525b7dc2193843e8dfebf799")
ACCOUNT_GUARD capability defined: (taken from kitty-kad contract)
(defcap ACCOUNT_GUARD(account:string) ; Used for admin functions
@doc "Verifies account meets format and belongs to caller"
(enforce (= "k:" (take 2 account)) "For security, only support k: accounts")
(enforce-guard
(at "guard" (coin.details account))
)
)
A simplified mint-nft is defined as follows:
(defun mint-nft()
@doc "Allows any k: address to mint an nft"
(require-capability (ACCOUNT_GUARD (at "sender" (chain-data))))
(insert nft-main-table id {
"id":id,
"generation":0,
"owner-address":(at "sender" (chain-data))
})
)
From my understanding, ACCOUNT_GUARD is simply checking to see that the account calling the contract is a valid k: address and that the account calling it is the owner of said account.
Why would the ACCOUNT_GUARD not be granted to the caller of (mint-nft) in this case?
How do I grant the ACCOUNT_GUARD capability to any user that calls (mint-nft)?
Capabilities must be acquired before require-capability
will succeed. See https://pact-language.readthedocs.io/en/stable/pact-reference.html#expressing-capabilities-in-code-defcap for discussion of this.
Capabilities are acquired with with-capability
such that code within the body of the with-capability
expression have the granted capability in scope. At that point you could call mint-nft
, if that was a "protected function" that you did not want users to call at top level.
However if mint-nft
is the intended top-level call, then use with-capability
instead of require-capability
, and include the insert
call in the body. (Your indentation already looks like this even though there is no body in require-capability
btw).
Lastly, you should not base anything on sender
-- this is the gas payer only and in Kadena gas can be paid by a gas station or really anybody. Instead you should manage a user table with the associated guard, and validate the principal when creating the user. k:
without any associated guard is meaningless.