Skip to content

Commit

Permalink
Add string handling functions
Browse files Browse the repository at this point in the history
  • Loading branch information
elmato committed May 13, 2020
1 parent 5037491 commit fdb27a2
Show file tree
Hide file tree
Showing 5 changed files with 356 additions and 34 deletions.
57 changes: 31 additions & 26 deletions evolutiondex.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "evolutiondex.hpp"
#include "utils.hpp"

using namespace evolution;

Expand Down Expand Up @@ -31,17 +32,24 @@ void evolutiondex::closeext( const name& user, const name& to, const extended_sy
}

void evolutiondex::deposit(name from, name to, asset quantity, string memo) {

constexpr string_view DEPOSIT_TO = "deposit to:";
constexpr string_view EXCHANGE = "exchange:";

if (from == get_self()) return;
check(to == get_self(), "This transfer is not for evolutiondex");
check(quantity.amount >= 0, "quantity must be positive");
if ( (memo.substr(0, 9)) == "exchange:") {
memoexchange(from, quantity, get_first_receiver(), memo.substr(9));

auto incoming = extended_asset{quantity, get_first_receiver()};

string_view memosv(memo);
if ( starts_with(memosv, EXCHANGE) ) {
memoexchange(from, incoming, memosv.substr(EXCHANGE.size()) );
} else {
if ( (memo.substr(0, 12)) == "deposit to: ") {
from = name(memo.substr(12));
if ( starts_with(memosv, DEPOSIT_TO) ) {
from = name(trim(memosv.substr(DEPOSIT_TO.size())));
check(from != get_self(), "Donation not accepted");
}
extended_asset incoming = extended_asset{quantity, get_first_receiver()};
add_signed_ext_balance(from, incoming);
}
}
Expand Down Expand Up @@ -147,36 +155,33 @@ void evolutiondex::exchange( name user, symbol_code through, asset asset1, asset
});
}

// details has the structure "EVOTOKN,min_expected_asset;memo"
void evolutiondex::memoexchange(name user, asset quantity, name contract, string details){
int comma = details.find(",");
check(comma != -1, "there must be a comma between evotoken symbol and min_expected_asset");
int semicolon = details.find(";");
check(semicolon > comma, "there must be a semicolon between min_expected_asset and memo");
string symbol_code_string = details.substr(0, comma);
string min_expected_asset_string = details.substr(comma + 1, semicolon - comma - 1);
string memo = details.substr(semicolon + 1);

int last_space = symbol_code_string.rfind(" ");
symbol_code_string = symbol_code_string.substr(last_space + 1);
auto through = symbol_code(symbol_code_string);
auto min_expected_asset = string_to_asset(min_expected_asset_string);
// details has the structure "EVOTOKN,min_expected_asset,memo"
void evolutiondex::memoexchange(name user, extended_asset amount, string_view details){
auto quantity = amount.quantity;
auto contract = amount.contract;

stats statstable( get_self(), through.raw() );
const auto& token = statstable.find( through.raw() );
auto parts = split(details, ",");
check(parts.size() >= 2 && parts.size() <= 3, "Expected format 'EVOTOKEN,min_expected_asset,memo'");

auto evo_token = symbol_code(parts[0]);
auto min_expected = asset_from_string(parts[1]);
auto memo = std::string(parts.size() == 3 ? parts[2] : "");

stats statstable( get_self(), evo_token.raw() );
const auto token = statstable.find( evo_token.raw() );
check ( token != statstable.end(), "token does not exist" );
bool in_first;
if ((token->pool1.quantity.symbol == quantity.symbol) &&
(token->pool2.quantity.symbol == min_expected_asset.symbol)) {
(token->pool2.quantity.symbol == min_expected.symbol)) {
in_first = true;
check(token->pool1.contract == contract, "you are transfering from an incorrect contract");
// testear estos mandando desde otros contratos.
} else if ((token->pool2.quantity.symbol == quantity.symbol) &&
(token->pool1.quantity.symbol == min_expected_asset.symbol)) {
(token->pool1.quantity.symbol == min_expected.symbol)) {
in_first = false;
check(token->pool2.contract == contract, "you are transfering from an incorrect contract");
}
else check(false, "symbol mismatch");
else check(false, "symbol mismatch");
int64_t P_in, P_out;
if (in_first) {
P_in = token-> pool1.quantity.amount;
Expand All @@ -187,7 +192,7 @@ void evolutiondex::memoexchange(name user, asset quantity, name contract, string
}
auto A_in = quantity.amount;
int64_t A_out = compute(-A_in, P_out, P_in + A_in, token->fee);
check(min_expected_asset.amount <= -A_out, "available is less than expected");
check(min_expected.amount <= -A_out, "available is less than expected");
extended_asset ext_asset1, ext_asset2, ext_asset_out;
if (in_first) {
ext_asset1 = extended_asset{A_in, token-> pool1.get_extended_symbol()};
Expand All @@ -203,7 +208,7 @@ void evolutiondex::memoexchange(name user, asset quantity, name contract, string
a.pool2 += ext_asset2;
});
action(permission_level{ get_self(), "active"_n }, ext_asset_out.contract, "transfer"_n,
std::make_tuple( get_self(), user, ext_asset_out.quantity, memo) ).send();
std::make_tuple( get_self(), user, ext_asset_out.quantity, std::string(memo)) ).send();
}

asset evolutiondex::string_to_asset(string input) {
Expand Down
2 changes: 1 addition & 1 deletion evolutiondex.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ namespace evolution {

void add_signed_ext_balance( const name& owner, const extended_asset& value );
void add_signed_liq(name user, asset to_buy, bool is_buying, asset max_asset1, asset max_asset2);
void memoexchange(name user, asset quantity, name contract, string details);
void memoexchange(name user, extended_asset amount, string_view details);
int64_t compute(int64_t x, int64_t y, int64_t z, int fee);
asset string_to_asset(string input);

Expand Down
221 changes: 221 additions & 0 deletions safe.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
#pragma once

#include <limits>
/**
* This type is designed to provide automatic checks for
* integer overflow and default initialization. It will
* throw an exception on overflow conditions.
*
* It can only be used on built-in types. In particular,
* safe<uint128_t> is buggy and should not be used.
*
* Implemented using spec from:
* https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
*/
template<typename T>
struct safe
{
T value = 0;

template<typename O>
safe( O o ):value(o){}
safe(){}
safe( const safe& o ):value(o.value){}

static safe min()
{
return std::numeric_limits<T>::min();
}
static safe max()
{
return std::numeric_limits<T>::max();
}

friend safe operator + ( const safe& a, const safe& b )
{
if( b.value > 0 && a.value > (std::numeric_limits<T>::max() - b.value) ) check(false, "overflow_exception, (a)(b)" );
if( b.value < 0 && a.value < (std::numeric_limits<T>::min() - b.value) ) check(false, "underflow_exception, (a)(b)" );
return safe( a.value + b.value );
}
friend safe operator - ( const safe& a, const safe& b )
{
if( b.value > 0 && a.value < (std::numeric_limits<T>::min() + b.value) ) check(false, "underflow_exception, (a)(b)" );
if( b.value < 0 && a.value > (std::numeric_limits<T>::max() + b.value) ) check(false, "overflow_exception, (a)(b)" );
return safe( a.value - b.value );
}

friend safe operator * ( const safe& a, const safe& b )
{
if( a.value > 0 )
{
if( b.value > 0 )
{
if( a.value > (std::numeric_limits<T>::max() / b.value) ) check(false, "overflow_exception, (a)(b)" );
}
else
{
if( b.value < (std::numeric_limits<T>::min() / a.value) ) check(false, "underflow_exception, (a)(b)" );
}
}
else
{
if( b.value > 0 )
{
if( a.value < (std::numeric_limits<T>::min() / b.value) ) check(false, "underflow_exception, (a)(b)" );
}
else
{
if( a.value != 0 && b.value < (std::numeric_limits<T>::max() / a.value) ) check(false, "overflow_exception, (a)(b)" );
}
}

return safe( a.value * b.value );
}

friend safe operator / ( const safe& a, const safe& b )
{
if( b.value == 0 ) check(false, "divide_by_zero_exception, (a)(b)" );
if( a.value == std::numeric_limits<T>::min() && b.value == -1 ) check(false, "overflow_exception, (a)(b)" );
return safe( a.value / b.value );
}
friend safe operator % ( const safe& a, const safe& b )
{
if( b.value == 0 ) check(false, "divide_by_zero_exception, (a)(b)" );
if( a.value == std::numeric_limits<T>::min() && b.value == -1 ) check(false, "overflow_exception, (a)(b)" );
return safe( a.value % b.value );
}

safe operator - ()const
{
if( value == std::numeric_limits<T>::min() ) check(false, "overflow_exception, (*this)" );
return safe( -value );
}

safe& operator += ( const safe& b )
{
value = (*this + b).value;
return *this;
}
safe& operator -= ( const safe& b )
{
value = (*this - b).value;
return *this;
}
safe& operator *= ( const safe& b )
{
value = (*this * b).value;
return *this;
}
safe& operator /= ( const safe& b )
{
value = (*this / b).value;
return *this;
}
safe& operator %= ( const safe& b )
{
value = (*this % b).value;
return *this;
}

safe& operator++()
{
*this += 1;
return *this;
}
safe operator++( int )
{
safe bak = *this;
*this += 1;
return bak;
}

safe& operator--()
{
*this -= 1;
return *this;
}
safe operator--( int )
{
safe bak = *this;
*this -= 1;
return bak;
}

friend bool operator == ( const safe& a, const safe& b )
{
return a.value == b.value;
}
friend bool operator == ( const safe& a, const T& b )
{
return a.value == b;
}
friend bool operator == ( const T& a, const safe& b )
{
return a == b.value;
}

friend bool operator < ( const safe& a, const safe& b )
{
return a.value < b.value;
}
friend bool operator < ( const safe& a, const T& b )
{
return a.value < b;
}
friend bool operator < ( const T& a, const safe& b )
{
return a < b.value;
}

friend bool operator > ( const safe& a, const safe& b )
{
return a.value > b.value;
}
friend bool operator > ( const safe& a, const T& b )
{
return a.value > b;
}
friend bool operator > ( const T& a, const safe& b )
{
return a > b.value;
}

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

friend bool operator <= ( const safe& a, const safe& b )
{
return !(a > b);
}
friend bool operator <= ( const safe& a, const T& b )
{
return !(a > b);
}
friend bool operator <= ( const T& a, const safe& b )
{
return !(a > b);
}

friend bool operator >= ( const safe& a, const safe& b )
{
return !(a < b);
}
friend bool operator >= ( const safe& a, const T& b )
{
return !(a < b);
}
friend bool operator >= ( const T& a, const safe& b )
{
return !(a < b);
}
};
15 changes: 8 additions & 7 deletions tests/evolutiondex_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ static symbol EOS = symbol::from_string("4,EOS");
static symbol VOICE = symbol::from_string("4,VOICE");
static symbol TUSD = symbol::from_string("4,TUSD");

BOOST_AUTO_TEST_SUITE(eosio_token_tests)
BOOST_AUTO_TEST_SUITE(evolutiondex_tests)

BOOST_FIXTURE_TEST_CASE( evo_tests, evolutiondex_tester ) try {
const auto& accnt2 = control->db().get<account_object,by_name>( N(evolutiondex) );
Expand Down Expand Up @@ -552,10 +552,11 @@ BOOST_FIXTURE_TEST_CASE( memoexchange_test, evolutiondex_tester ) try {
transfer( N(eosio.token), N(alice), N(evolutiondex), asset{4500000000000000000, TUSD}, "");
transfer( N(eosio.token), N(alice), N(bob), asset{30000000000000000, TUSD}, "");

inittoken( N(alice), EVO,
extended_asset{asset{230584300921369, EOS}, N(eosio.token)},
extended_asset{asset{961168601842738, VOICE}, N(eosio.token)},
12, N(wevotethefee));
BOOST_REQUIRE_EQUAL( success(),
inittoken( N(alice), EVO,
extended_asset{asset{230584300921369, EOS}, N(eosio.token)},
extended_asset{asset{461168601842738, VOICE}, N(eosio.token)},
12, N(wevotethefee)) );

BOOST_REQUIRE_EQUAL( wasm_assert_msg("symbol mismatch"),
transfer( N(eosio.token), N(alice), N(evolutiondex), asset{40000, EOS},
Expand Down Expand Up @@ -584,13 +585,13 @@ BOOST_FIXTURE_TEST_CASE( memoexchange_test, evolutiondex_tester ) try {

auto old_vec = system_balance(5199429);
transfer( N(eosio.token), N(alice), N(evolutiondex), asset{40000, EOS},
"exchange: EVO, 10000 VOICE; nothing to say");
"exchange: EVO, 10000 VOICE, nothing to say");
auto new_vec = system_balance(5199429);
BOOST_REQUIRE_EQUAL(is_increasing(old_vec, new_vec), true);

old_vec = system_balance(293455877189);
transfer( N(eosio.token), N(bob), N(evolutiondex), asset{3000000000000000000, TUSD},
"exchange: ETUSD, 40000000000000 EOS;");
"exchange: ETUSD, 40000000000000 EOS,");
new_vec = system_balance(293455877189);
BOOST_REQUIRE_EQUAL(is_increasing(old_vec, new_vec), true);
} FC_LOG_AND_RETHROW()
Expand Down
Loading

0 comments on commit fdb27a2

Please sign in to comment.