How to define a singleton

To define a simple singleton, which is storing an account name as primary value and a uint64_t as secondary value in structure testtable, follow the steps below:

1.Include the arisen.hpp and singleton.hpp headers and declare the arisen namespace usage

#include <arisen/arisen.hpp>
#include <arisen/singleton.hpp>
using namespace arisen;

Define the data structure for the multi index table

struct [[arisen::table]] testtable {
   name primary_value;
   uint64_t secondary_value;
};

For ease of use, define a type alias singleton_type based on the arisen::singleton template type, parametarized with a random name "testsingletona" and the testtable data structure defined above

struct [[arisen::table]] testtable {
   name primary_value;
   uint64_t secondary_value;
};
+using singleton_type = arisen::singleton<"testsingletona"_n, testtable>;
struct [[arisen::table]] testtable {
   name primary_value;
   uint64_t secondary_value;
};

using singleton_type = arisen::singleton<"testsingletona"_n, testtable>;
+singleton_type singleton_instance;

singleton_example.hpp

#include <arisen/arisen.hpp>
#include <arisen/singleton.hpp>
using namespace arisen;

class [[arisen::contract]] singleton_example : public contract {
   public:
      using contract::contract;
      singleton_example( name receiver, name code, datastream<const char*> ds ) :
         contract(receiver, code, ds),
         singleton_instance(receiver, receiver.value)
         { }

      [[arisen::action]] void set( name user, uint64_t value );
      [[arisen::action]] void get( );

      struct [[arisen::table]] testtable {
         name primary_value;
         uint64_t secondary_value;
      } tt;

      using singleton_type = arisen::singleton<"testsingletona"_n, testtable>;
      singleton_type singleton_instance;

      using set_action = action_wrapper<"set"_n, &singleton_example::set>;
      using get_action = action_wrapper<"get"_n, &singleton_example::get>;
};

And below is a possible implementation for the two get and set actions defined above. It also demonstrates the usage of a couple of singleton methods. Note that the set action makes use of the singleton's set method, for which parameter is the account to pay for the new value stored. In this case, the same account name that is stored in the primary value is the payer. However, it can be a different account if so required.

singleton_example.cpp

#include <singleton_example.hpp>

[[arisen::action]] void singleton_example::set( name user, uint64_t value ) {
   if (!singleton_instance.exists())
   {
      singleton_instance.get_or_create(user, tt);
   }
   auto entry_stored = singleton_instance.get();
   entry_stored.primary_value = user;
   entry_stored.secondary_value = value;
   singleton_instance.set(entry_stored, user);
}

[[arisen::action]] void singleton_example::get( ) {
   if (singleton_instance.exists())
      arisen::print(
         "Value stored for: ", 
         name{singleton_instance.get().primary_value.value},
         " is ",
         singleton_instance.get().secondary_value,
         "\n");
   else
      arisen::print("Singleton is empty\n");
}

📘

Full example location

A full example project demonstrating the instantiation and usage of singleton can be found here.