2

Is it possible to include in a payable function a message such as "Transaction rejected - Company not registered" which is displayed when a transaction is rejected? My code is as per below:

    pragma solidity ^0.4.24;

contract KYCPurchase {
  uint public price = 2 ether;

  struct Company {
      string registeredNumber;
      string name;
  }
  mapping (address => Company) companies;

  function buy(string registeredNumber, string name) public payable {
    require(msg.value >= price);

    // Keep a list of buyers who have transferred enough ether
    companies[msg.sender] = Company(registeredNumber, name);
  }
}

Thanks

1

Sure, but with caveats.

You should resist the temptation to explain. These are immutable contracts. The priority is reliability, and simplicity is the first line of defense. If that means being obtuse to client software, so be it. "Fail early. Fail hard" is a best practice. This is intuitively opposite of the approach used in most environments where there is a near obsession with avoiding a system crash - error traps, message handlers, etc.. A Solidity contract should seize every opportunity to crash.

Take, for example, the simple case of a failed value transfer. The original .send() method returned false in the case of a failed transfer. The problem was that many devs proceded on the assumption that a transfer never failed, so overlooked the need to check the result. That led to code like this:

address.send(amount);

When it should have been:

if(!address.sender(amount)) throw; // or revert();

The lesson there was that returning false burdens the caller with dealing with exceptions. The situation is only more burdensome when multiple responses are possible.

if(response == 1) { ...
if(response == 2) { ...
if(response == 3) { ...

In this respect, a hard stop with revert() (or require()) actually helps clients by rejecting transactions (in their entirety) if something doesn't validate.

This situation is a nuisance from a developer standpoint because failed transactions can't even emit events a developer might want to see for troubleshooting purposes. Keeping "Fail early. Fail hard" in mind, developer convenience is not a good reason, in my opinion, to produce code that looks like this:

contract Callee {

  function doSomething() public returns(uint responseCode) {
    if(something()) return 1;
    if(somethingElse()) return 2;
    if(theOtherThing()) return 3;
    return 4;
  }
}

contract Caller {
  function callCallee() public returns(uint responseCode) {
    uint response = callee.doSomething();
    if(response == 1) { ...
    if(response == 2) { ...
...

It's easy to see that the idiomatic purpose of the process will get lost in the exception handling, and that is not good. Not to mention gas.

As of Solidity 4.21(?) you can revert or require with a reason.

require(msg.value >= price, "Insufficient funds);

This is still a hard stop with full transaction reversion, which is what we usually want. Now, with a message to indicate which condition caused it.

An example that displays the reason in Remix.

pragma solidity 0.5.1;

contract Reason {

    function doSomething() public pure {
        require(false, "Just because");
    }
}

Hope it helps.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.