Skip to main content

libraries/eosiolib/core/eosio/asset.hpp

Namespaces

Name
eosio

Classes

Name
structeosio::asset
structeosio::extended_asset

Source code

#pragma once

#include "serialize.hpp"
#include "print.hpp"
#include "check.hpp"
#include "symbol.hpp"

#include <tuple>
#include <limits>

namespace eosio {

char* write_decimal( char* begin, char* end, bool dry_run, uint64_t number, uint8_t num_decimal_places, bool negative );

struct asset {
int64_t amount = 0;

symbol symbol;

static constexpr int64_t max_amount = (1LL << 62) - 1;

asset() {}

asset( int64_t a, class symbol s )
:amount(a),symbol{s}
{
eosio::check( is_amount_within_range(), "magnitude of asset amount must be less than 2^62" );
eosio::check( symbol.is_valid(), "invalid symbol name" );
}

bool is_amount_within_range()const { return -max_amount <= amount && amount <= max_amount; }

bool is_valid()const { return is_amount_within_range() && symbol.is_valid(); }

void set_amount( int64_t a ) {
amount = a;
eosio::check( is_amount_within_range(), "magnitude of asset amount must be less than 2^62" );
}


asset operator-()const {
asset r = *this;
r.amount = -r.amount;
return r;
}

asset& operator-=( const asset& a ) {
eosio::check( a.symbol == symbol, "attempt to subtract asset with different symbol" );
amount -= a.amount;
eosio::check( -max_amount <= amount, "subtraction underflow" );
eosio::check( amount <= max_amount, "subtraction overflow" );
return *this;
}

asset& operator+=( const asset& a ) {
eosio::check( a.symbol == symbol, "attempt to add asset with different symbol" );
amount += a.amount;
eosio::check( -max_amount <= amount, "addition underflow" );
eosio::check( amount <= max_amount, "addition overflow" );
return *this;
}

inline friend asset operator+( const asset& a, const asset& b ) {
asset result = a;
result += b;
return result;
}

inline friend asset operator-( const asset& a, const asset& b ) {
asset result = a;
result -= b;
return result;
}

asset& operator*=( int64_t a ) {
int128_t tmp = (int128_t)amount * (int128_t)a;
eosio::check( tmp <= max_amount, "multiplication overflow" );
eosio::check( tmp >= -max_amount, "multiplication underflow" );
amount = (int64_t)tmp;
return *this;
}

friend asset operator*( const asset& a, int64_t b ) {
asset result = a;
result *= b;
return result;
}


friend asset operator*( int64_t b, const asset& a ) {
asset result = a;
result *= b;
return result;
}

asset& operator/=( int64_t a ) {
eosio::check( a != 0, "divide by zero" );
eosio::check( !(amount == std::numeric_limits<int64_t>::min() && a == -1), "signed division overflow" );
amount /= a;
return *this;
}

friend asset operator/( const asset& a, int64_t b ) {
asset result = a;
result /= b;
return result;
}

friend int64_t operator/( const asset& a, const asset& b ) {
eosio::check( b.amount != 0, "divide by zero" );
eosio::check( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" );
return a.amount / b.amount;
}

friend bool operator==( const asset& a, const asset& b ) {
eosio::check( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" );
return a.amount == b.amount;
}

friend bool operator!=( const asset& a, const asset& b ) {
return !( a == b);
}

friend bool operator<( const asset& a, const asset& b ) {
eosio::check( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" );
return a.amount < b.amount;
}

friend bool operator<=( const asset& a, const asset& b ) {
eosio::check( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" );
return a.amount <= b.amount;
}

friend bool operator>( const asset& a, const asset& b ) {
eosio::check( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" );
return a.amount > b.amount;
}

friend bool operator>=( const asset& a, const asset& b ) {
eosio::check( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" );
return a.amount >= b.amount;
}


char* write_as_string( char* begin, char* end, bool dry_run = false )const {
bool negative = (amount < 0);
uint64_t abs_amount = static_cast<uint64_t>(negative ? -amount : amount);
// 0 <= abs_amount <= std::numeric_limits<int64_t>::max() < 10^19 < std::numeric_limits<uint64_t>::max()

uint8_t precision = symbol.precision();

int sufficient_size = std::max(static_cast<int>(precision), 19) + 11;
if( dry_run || (begin + sufficient_size < begin) || (begin + sufficient_size > end) ) {
char* start_of_symbol = write_decimal( begin, end, true, abs_amount, precision, negative ) + 1;
char* actual_end = symbol.code().write_as_string( start_of_symbol, end, true );
if( dry_run || (actual_end < begin) || (actual_end > end) ) return actual_end;
}

char* end_of_number = write_decimal( begin, end, false, abs_amount, precision, negative );
*(end_of_number) = ' ';

return symbol.code().write_as_string( end_of_number + 1, end );
}

std::string to_string()const {
int buffer_size = std::max(static_cast<int>(symbol.precision()), 19) + 11;
char buffer[buffer_size];
char* end = write_as_string( buffer, buffer + buffer_size );
check( end <= buffer + buffer_size, "insufficient space in buffer" ); // should never fail

return {buffer, end};
}

void print()const {
int buffer_size = std::max(static_cast<int>(symbol.precision()), 19) + 11;
char buffer[buffer_size];
char* end = write_as_string( buffer, buffer + buffer_size );
check( end <= buffer + buffer_size, "insufficient space in buffer" ); // should never fail

if( buffer < end )
printl( buffer, (end-buffer) );
}

EOSLIB_SERIALIZE( asset, (amount)(symbol) )
};

struct extended_asset {
asset quantity;

name contract;

extended_symbol get_extended_symbol()const { return extended_symbol{ quantity.symbol, contract }; }

extended_asset() = default;

extended_asset( int64_t v, extended_symbol s ):quantity(v,s.get_symbol()),contract(s.get_contract()){}
extended_asset( asset a, name c ):quantity(a),contract(c){}

void print()const {
quantity.print();
::eosio::print("@", contract);
}


// Unary minus operator
extended_asset operator-()const {
return {-quantity, contract};
}

// Subtraction operator
friend extended_asset operator - ( const extended_asset& a, const extended_asset& b ) {
eosio::check( a.contract == b.contract, "type mismatch" );
return {a.quantity - b.quantity, a.contract};
}

// Addition operator
friend extended_asset operator + ( const extended_asset& a, const extended_asset& b ) {
eosio::check( a.contract == b.contract, "type mismatch" );
return {a.quantity + b.quantity, a.contract};
}

friend extended_asset& operator+=( extended_asset& a, const extended_asset& b ) {
eosio::check( a.contract == b.contract, "type mismatch" );
a.quantity += b.quantity;
return a;
}

friend extended_asset& operator-=( extended_asset& a, const extended_asset& b ) {
eosio::check( a.contract == b.contract, "type mismatch" );
a.quantity -= b.quantity;
return a;
}

friend bool operator<( const extended_asset& a, const extended_asset& b ) {
eosio::check( a.contract == b.contract, "type mismatch" );
return a.quantity < b.quantity;
}


friend bool operator==( const extended_asset& a, const extended_asset& b ) {
return std::tie(a.quantity, a.contract) == std::tie(b.quantity, b.contract);
}

friend bool operator!=( const extended_asset& a, const extended_asset& b ) {
return std::tie(a.quantity, a.contract) != std::tie(b.quantity, b.contract);
}

friend bool operator<=( const extended_asset& a, const extended_asset& b ) {
eosio::check( a.contract == b.contract, "type mismatch" );
return a.quantity <= b.quantity;
}

friend bool operator>=( const extended_asset& a, const extended_asset& b ) {
eosio::check( a.contract == b.contract, "type mismatch" );
return a.quantity >= b.quantity;
}


EOSLIB_SERIALIZE( extended_asset, (quantity)(contract) )
};
}

Updated on 2022-12-05 at 15:38:08 +0000