Wax Smart Contract Development Guide
  • WAX Smart Contract Development Guide
  • Tips And Tricks
    • Table Indexing
    • eosio.code Permission
    • Structuring Your Contract
    • Random Number Generation
    • uint8_t + enum For Statuses
    • Passing Iterators To Functions
    • Log Actions
    • Action Return Values
    • Readonly Actions
    • Debugging
    • Having Users Pay RAM
    • Inline Actions
    • Renouncing Contract Ownership
    • Creating Permission Structures
  • Tools
    • Self Audit Checklist
    • Unit Tests
Powered by GitBook
On this page
  1. Tips And Tricks

uint8_t + enum For Statuses

This one is more of a little tip/trick that I like to use - it's not necessarily something you need to know in order to write smart contracts.

There are plenty of times where you'll need to store some type of status in a table, or struct. True/false, open/closed, etc. Since you can't modify table structures without going through a complicated process, I've learned over the years that it's best to always plan in advance, and allow for the possibility that you might need more than 2 options.

For this reason, I use uint8_t to store these values, instead of a boolean. Then I combine this with an enum in order to improve code clarity / readability.

Let's pretend for example that you have some actions on your contract, and you only want specific users to be able to execute these actions. So, you put a flag in your table called is_authorized, like this.

struct [[eosio::table, eosio::contract(CONTRACT_NAME)]] users {
	eosio::name		wallet;
	bool  			is_authorized;				

	uint64_t primary_key() const { return wallet.value; }
};
using users_table = eosio::multi_index<"users"_n, users>;

The problem you will eventually run into, is that you might add some new action to your contract, which requires higher authorization than a regular user, but less authorization than the users you originally created this flag for. Well, now you have no way of adding a 3rd option.

This is the reason that I use uint8_t instead.

struct [[eosio::table, eosio::contract(CONTRACT_NAME)]] users {
	eosio::name		wallet;
	uint8_t  		is_authorized;				
	// 0: not authorized
	// 1: has all privileges
	// 2: has some privileges but not all
	// 3: is_blacklisted
	// Can add more options as needed
	
	uint64_t primary_key() const { return wallet.value; }
};
using users_table = eosio::multi_index<"users"_n, users>;

With this approach, your contract remains flexible and is able to adapt to any new features you may add in the future. If you were simply using a bool, you would've had to create a new table in order to extend the current privilege structure.

There is a problem here, though. When other parts of your contract are comparing against uint8_t to determine a status, it becomes difficult to keep track of what each number is supposed to mean. This is where enums come into play.

static const enum AUTH_TYPES { 
	NOT_AUTHORIZED, 
	ALL_PRIVILEGES, 
	SOME_PRIVILEGES, 
	BLACKLISTED };

struct [[eosio::table, eosio::contract(CONTRACT_NAME)]] users {
	eosio::name		wallet;
	uint8_t  		is_authorized;				

	uint64_t primary_key() const { return wallet.value; }
};
using users_table = eosio::multi_index<"users"_n, users>;

ACTION mycontract::dosomething(){
	users_table users_t = users_table( _self, _self.value );
	auto itr = users_t.require_find( some_user.value );
	
	// Checking their auth
	if( itr->is_authorized == uint8_t(BLACKLISTED) ){
		check(false, "you are blacklisted");
	}
	
	// Modifying their auth
	users_t.modify(itr, same_payer, [&](auto &_user){
		_user.is_authorized = uint8_t(SOME_PRIVILEGES);
	});
}

This allows you to use uint8_t for storage, but also allows you to keep the code clean and readable, which is always important (for yourself and for other developers).

PreviousRandom Number GenerationNextPassing Iterators To Functions

Last updated 10 months ago