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