I have a table of prices where I want to store 2 prices per cross defined like this:

struct [[eosio::table]] _prices {
    symbol base;
    symbol quote;
    float value = 0.0;
    uint128_t primary_key() const {
        return base.code().raw() << 64 | quote.code().raw();

originally the primary key was defined to return base.code().raw() + quote.code().raw() but that approached produced constraint violations:

could not insert object, most likely a uniqueness constraint was violated

because adding "USD" to "EUR" is (I guess) the same as adding "EUR" to "USD"... so what I need is to use "USDEUR" or "EURUSD" as the primary key

the problem is that since these are represented as integers, I need to shift, and since each of the components is 64bits in width (as per the symbol definition) then the composite must be 128 bit long, which produces a warning when compiling:

./token.hpp:154:30: warning: shift count >= width of type [-Wshift-count-overflow] return base.code().raw() << 64 | quote.code().raw();

and moreover doesn't work. what is the recommended approach to creating composite keys?

addendum I

of course, it would be great to just define the return value as a string (so I could concatenate the strings together), but it demands an integer. I get this error:

/usr/local/Cellar/eosio.cdt/1.5.0/opt/eosio.cdt/bin/../include/libcxx/memory:1759:31: error: no matching constructor for initialization of 'eosio::multi_index<12528034910801231872, eosio::token::_prices>::item_ptr'

1 Answer 1


the problem is that the primary key index cannot be 128 bits long. it must be 64 bits. but other indexes can be 128 bits

so my solution was to implement an auto-generated monotonic primary key and then define the index I wanted as a secondary index

struct [[eosio::table]] _prices {
    uint64_t id;
    symbol base;
    symbol quote;
    uint64_t primary_key() const {
        return id;
    uint128_t idxwhatever() const {
        return base.code().raw() << 64 | quote.code().raw();

typedef eosio::multi_index<
    name("prices"), _prices, 
        const_mem_fun<_prices, uint128_t, &_prices::idxwhatever>
> prices;

which means inserts into the table need a value for the PK. I do this with something like:

prices p(_self, _self.value);
p.emplace(_self, [&](auto &r) {
    r.id = p.available_primary_key();

and then need to use the index:

prices p(_self, _self.value);
auto myindex = p.get_index<name("idxwhatever")>();

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.