Imagine that I have a contract where a user can buy and sell tokens based on a dynamic price in ETH.

The price is calculated every 2 hours by a server. When buying or selling, the value used is the next one that will be produced in the future (not the past ones). This means that there will be 2 steps to buy tokens: requestBuy to send the ETH and save the request on a mapping for sender's address, and executeBuy to convert the amount to tokens based on the price and send it to the buyer (same for selling).

  • requestBuy is called by the client.
  • executeBuy is called by the server.


Should the owner write the price into the contract and call executeBuy or should send the price as an argument to executeBuy? What are the trade-offs for each one?

Main criteria: transparency of price history in the contract vs public API

  • You've asked what's "best" without defining any criteria. E.g. #3 and #4 differ in who pays for gas. Which is better depends on whether you think it's better for the users to pay for gas or for a centralized account to pay for gas.
    – user19510
    Feb 22, 2018 at 11:14
  • re-wrote the question to be more clear
    – banzap
    Feb 22, 2018 at 14:04

2 Answers 2


Your idea is that users request to buy tokens and deposit some amount of ETH without knowing how many (if any) tokens they will get for their money.

Why don't you create a function called updatePrice that enables the owner to store the current price in the smart contract. Every user can then see how many tokens they would get for their ETH. Also calling buy would be instantaneous because the price is already fixed and no one needs to approve the transaction. This also saves transaction fees for the owner.

The most transparent way would obviously be to calculate the price in the contract, but that might be impossible for your specific usecase.

  • prices are updated each hour (or 2 hours or per day, depending on configuration). if you buy now, you are gonna pay the price available in the next hour (that's how it works for this use case). that's why there I need an execute method to send the price and execute the buy when the price is created. so is impossible for the user to know for sure how many tokens will get, it will only know more or less how much based on past data
    – banzap
    Feb 22, 2018 at 15:53
  • using oraclize was another solution. however, in my case won't be possible.
    – banzap
    Feb 22, 2018 at 15:54
  • Okay, then it doesn't matter in which order you do it. Sending it as an argument would be cheaper. Feb 22, 2018 at 16:01
  • I agree the most transparent calculation will be in the contract but currently isn't feasible. that's why I'm trying to raise the question if having the price history would make sense in the contract to be a bit more transparent but might not be worth
    – banzap
    Feb 22, 2018 at 16:13
  • Price history can be seen when you look at past transactions on etherscan Feb 22, 2018 at 18:34

I have a similar use case (and it regards a commodity whose price is updated twice daily).

What we do is we have two methods to set the bid price and the ask price (sell price, buy price) of the commodity. This can only be called by the admin. We have set our server to have admin rights on the contract and when the international price of the commodity gets updated, we add our margin to the international price of the commodity and then use web3.py to update the bid/ask prices on the contract itself. In our case we update the bid prices twice daily, but theoretically, you can call these bid_update ask_update methods as often as you wish (it will just cost you gas).

We then have two methods called buy and sell which reference the different bid, ask prices set previously by the admin and allow clients to deposit any ERC20 token and convert this to our ERC20 token which then gets sent to them by the contract itself.

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.