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?
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.