I need to implement allowance() function of Solidity, how can we achieve it in SmartPy?

  • Are you talking about native tez or a FA token?
    – Jordan_tez
    Commented Apr 12, 2023 at 16:02
  • Here I am mainly looking for FA token but it you could suggest for both it would be even great.
    – theBatMan
    Commented Apr 12, 2023 at 16:22

1 Answer 1


Here are the status for the 3 main fungible asset (FA) norms:

  • FA1.2 (tend to be obsolete): there is an allowance system, see the corresponding template.
  • FA2 (currently used): there is no allowance system by default but an operator system. You can
    1. Do it similarly to most Tezos contract by following these steps (it's better if done in the same transaction): 1) The user calls update_operators and adds the contract as operator 2) The user calls the contract. 3) The contract uses the operator privilege to move the tokens 4) The user checks that the contract hasn't done any unwanted move. 5) The user removes the operator privilege.
    2. Inherit from the FA2 library base class, add an allowance big_map and a set_allowance entrypoint and replace the transfer entrypoint by a custom one, see below.
  • FA2.1: This proposal may add (or not, that's being discussed) an allowance mechanism. It will also probably include a mechanism to transfer tokens with tickets that provides a better system than the allowance.

The custom transfer entrypoint for FA2:

def transfer(self, batch):
    """Accept a list of transfer operations between a source and multiple
    Custom version with allowance system.

    `transfer_tx_` must be defined in the child class.
    sp.set_type(batch, t_transfer_params)
    if self.policy.supports_transfer:
        with sp.for_("transfer", batch) as transfer:
            with sp.for_("tx", transfer.txs) as tx:
                # The ordering of sp.verify is important: 1) token_undefined, 2) transfer permission 3) balance
                sp.verify(self.is_defined(tx.token_id), "FA2_TOKEN_UNDEFINED")
                    self, transfer.from_, tx.to_, tx.token_id
                with sp.if_(sp.sender != transfer.from_):
                    self.update_allowance_(sp.sender, transfer.from_, tx.token_id, tx.amount)
                with sp.if_(tx.amount > 0):
                    self.transfer_tx_(transfer.from_, tx)

And the corresponding update_allowance_ method for Fa2SingleAsset:

def update_allowance_(self, spender, owner, token_id, amount):
    allowance = sp.record(spender=spender, owner=owner)
    self.data.allowances[allowance] = sp.as_nat(self.data.allowances.get(allowance, default=0) - amount, message=sp.pair("FA2_NOT_OPERATOR", "NoAllowance"))
  • can the above implementation be applied for all types of FA2 tokens? I am trying to implement it in FA2SingleAsset token.
    – theBatMan
    Commented Apr 12, 2023 at 17:20
  • Yes, and it's the easiest.
    – Jordan_tez
    Commented Apr 12, 2023 at 18:36
  • I updated my answer because the policy cannot take into account the amount transferred. So the solution I propose is to replace the transfer entrypoint by a custom one.
    – Jordan_tez
    Commented Apr 12, 2023 at 18:56
  • Do we have sp.spender attribute in smartpy ? Is it with sp.if_(sp.sender != transfer.from_): ? Isn't the data type of self.data.allowances is big_map?
    – theBatMan
    Commented Apr 20, 2023 at 5:11
  • I fixed my answer. Do not hesitate to mark it as valid if it's now good.
    – Jordan_tez
    Commented Apr 20, 2023 at 7:33

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.