How to charge fee in an entrypoint?

I want to be able to charge a fee through my contract, meaning collecting some tez (amount X) from sp.sender and perform an operation with 50% of X and collect the fee (to another address) for the remainder (50% of X in my assumption as well).
How can I do that?

Thank you!

I don’t know if there’s a specific method, but if I were you I will do something like this:

def feeExample(self, receiver):
    #send to receiver
    sp.send(receiver, (sp.amount/2))

    #collect fee
    sp.send(self.data.receiver, (sp.amount/2))

Bear in mind that the division can give you some type-error (Nat or Int), so you have to do more steps.

Thank you!
What is one of the recipient is a contract that will use the fee to run its own code?
I think I’m a bit stuck there too

If you mean you want to send tez to another contract you can use the contract address as well instead of wallet address.

So here’s my code below.
I think there are 2 errors.

  1. With the below code, I get a substraction underflow error. I assume it has to do with the fee as when I remove the related lines, the error is different.
  2. The second error I get is the balance too low error. I assume that it’s trying to transfer from the contract’s balance to the new contract.
    I might be wrong, but the reason I think that’s the case is that the error log tells me the balance is of 0.
        @sp.entrypoint
        def purchaseWithFee(self, address, param, price):
            sp.cast(price, sp.mutez)
            fee = sp.split_tokens(price, 1, 100)
            sp.send(self.data.recipientAddress, fee)
            sp.cast(param, sp.nat)
            contract = sp.contract(sp.nat, address, entrypoint="purchase")
            sp.transfer(
                param,
                price,
                contract.unwrap_some(error="Contract interface doesn't exist"))

Can you help me sort that out?
Thank you!

The second error cause is the one you thought, the balance of the contract is too low for the transaction.
About the first i’m not 100% sure but i think the problem is in calculation fee.
Is price more than 100?

How would I solve the first error then? Do I need to transfer the funds to the contract and then back?
Can’t I just transfer the balance of sp.amount - fee to the contract I call directly?

For the second, yes, price is a price in mutez. The sp.split_tokens(price, 1, 100) should calculate 1% of the of the price.

So to summarize, I need sp.sender to send price + fee, then transfer fee to a wallet A and price to a contract.

If you know how to achieve that with the new syntax, that would be great.

Thanks!

import smartpy as sp

class FeeTransfer(sp.Contract):
    def __init__(self, admin):
        self.init(admin = admin)

    @sp.entrypoint
    def purchaseWithFee(self, cAddress, param):
        #calculate fee
        fee = sp.split_tokens(sp.amount, 1, 100)
        #send fee
        sp.send(self.data.admin, fee)
        #send price
        c = sp.contract(sp.TNat, cAddress, entrypoint="purchase").open_some()
        sp.transfer(param, (sp.amount - fee) , c)


class ContractExample(sp.Contract):
    def __init__(self):
        self.init( param = sp.nat(0))

    @sp.entrypoint
    def purchase(self, param):
        self.data.param = param
        

@sp.add_test(name = "HTLC")
def testHTLC():
    #set scenario
    sc = sp.test_scenario()
    #create object FeeTransfer
    #create admin
    bob = sp.test_account("bob")
    ft = FeeTransfer(bob.address)
    #create object ContractExample
    ce = ContractExample()
    #start scenario
    sc += ft 
    sc += ce

    #create user
    alice = sp.test_account("alice")

    #first transfer
    ft.purchaseWithFee(sp.record(cAddress = ce.address, param = sp.nat(10))).run(sender = alice, amount = sp.mutez(1000))

I wrote this code on legacy edition. But if suits to you is easily convertible.

I use param as sp.nat just to be faster.

Let me know

1 Like

Deleting that here as it might be a better question in the other thread