0

I want to read available tezos balance of a given address. How do we achieve this in smartpy? Also do we have allowance() method like solidity in smartpy?

1 Answer 1

0

A smart contract can only know its own balance with the sp.balance instruction. There is no instruction in Tezos to get the balance of another account.

Mind you, there are ways to deal with this problem that result in a flaw in the contract (both for native and FA2 tokens including NFTs) as checking if someone owns something can be tricked by owning it during only a fraction of time.

There are ways to deal with this limitation:

  • Lock the tokens in an escrow contract (the link is provided for illustration purposes only).
  • Ask the address to transfer the tokens and then transfer them back (which may cause the flaw explained above).
  • Same as previous but use an intermediary contract that receives the coins, transfers them to the proof contract and return them to the owner. This adds extra guarantees for the sender that they will be given back their coins as long as they trust they intermediary contract (which may cause the flaw explained above).

Here is an illustrative example with the intermediary contract:

import smartpy as sp


@sp.module
def main():
    class Prover(sp.Contract):
        def __init__(self, flashSend):
            self.data.flashSend = flashSend
            self.data.proved = sp.big_map()

        @sp.entrypoint
        def prove(self):
            assert sp.sender == self.data.flashSend, "Sender is not flashSend"
            assert sp.amount > sp.tez(0), "Send tez via flashSend to prove that you own it"
            sp.send(sp.sender, sp.amount)
            self.data.proved[sp.source] = sp.amount

    class FlashSend(sp.Contract):
        def __init__(self):
            pass
            
        @sp.entrypoint
        def default(self):
            pass

        @sp.entrypoint
        def flashSend(self, receiver):
            sp.send(receiver, sp.amount)
            param = sp.record(amount=sp.amount)
            sp.transfer(param, sp.tez(0), sp.self_entrypoint("send_back"))

        @sp.entrypoint
        def send_back(self, param):
            assert sp.sender == sp.self_address()
            sp.send(sp.source, param.amount)

if "templates" not in __name__:

    @sp.add_test(name="MyContract")
    def test():
        alice = sp.test_account("alice")
        sc = sp.test_scenario(main)

        sc.h2("FlashSend")
        flashSend = main.FlashSend()
        sc += flashSend

        sc.h2("Prover")
        prover = main.Prover(flashSend.address)
        sc += prover

        flashSend.flashSend(
            sp.to_address(
                sp.contract(sp.TUnit, prover.address, entrypoint="prove").open_some()
            )).run(sender=alice, amount=sp.tez(50))

        sc.verify(prover.data.proved[alice.address] == sp.tez(50))
    

In a real life contract, I would add extra checks and ask an audit of the contract before anything else.

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.