Created
May 25, 2018 14:14
-
-
Save redjade/ca88d90e3f838c57ea7a1a287b23e30a to your computer and use it in GitHub Desktop.
bancor_test.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <cmath> | |
#include <iomanip> | |
#include <limits> | |
using namespace std; | |
class Connector { | |
public: | |
long double balance; | |
long double weight; | |
string symbol; | |
}; | |
class Supply { | |
public: | |
long double amount; | |
string symbol; | |
}; | |
class Asset { | |
public: | |
long double amount; | |
string symbol; | |
}; | |
class Bancor { | |
public: | |
Supply supply; | |
Connector base; | |
Connector quote; | |
string mode; | |
int debug; | |
Bancor() { | |
supply.amount = 100000000000000ll; | |
//supply.amount = 100000; | |
supply.symbol = "RAMCORE"; | |
base.balance = 1024.0 * 1024.0 * 1024.0 * 64.0; | |
//base.balance = 10000; | |
base.weight = 0.5; | |
base.symbol = "RAM"; | |
quote.balance = 1000000000ll / 1000.0; | |
//quote.balance = 5000; | |
quote.weight = 0.5; | |
quote.symbol = "CORE"; | |
} | |
void report() { | |
cout << supply.symbol << " " << supply.amount << endl; | |
cout << base.symbol << " " << base.balance << endl; | |
cout << quote.symbol << " " << quote.balance << endl; | |
} | |
Asset convert_to_exchange(Connector& c, Asset in) { | |
Asset asset; | |
long double R = supply.amount; | |
long double C; | |
if (mode == "hy") { | |
C = c.balance; | |
} else if (mode == "cur") { | |
C = c.balance + in.amount; | |
} else { | |
cout << "mode not defined" << endl; | |
} | |
if (debug) { | |
cout << "conn bal " << c.balance << endl; | |
cout << "conn bal + in.amount" << c.balance + in.amount << endl; | |
cout << "C in mode " << mode << " " << C << endl; | |
} | |
long double F = c.weight / 1000.0; | |
//long double F = c.weight; | |
long double T = in.amount; | |
long double E; | |
E = R * ( std::pow( 1.0 + T / C, F) - 1.0 ); | |
cout << "E " << E << endl; | |
supply.amount += E; | |
c.balance += T; | |
asset.amount = E; | |
asset.symbol = supply.symbol; | |
return asset; | |
} | |
Asset convert_from_exchange(Connector& c, Asset in) { | |
Asset asset; | |
long double R; | |
if (mode == "hy") { | |
R = supply.amount; | |
} else if (mode == "cur") { | |
R = supply.amount - in.amount; | |
} else { | |
cout << "mode not defined" << endl; | |
} | |
if (debug) { | |
cout << "sup bal " << supply.amount << endl; | |
cout << "sup bal - in.amount " << supply.amount - in.amount << endl; | |
cout << "R in mode " << mode << " " << R << endl; | |
} | |
long double C = c.balance; | |
long double F = 1000.0 / c.weight; | |
//long double F = 1.0 / c.weight; | |
long double E = in.amount; | |
long double T; | |
if (mode == "hy") { | |
T = -C * ( std::pow( 1.0 - E / R, F ) - 1.0 ); | |
//cout << "mode hy" << endl; | |
} else if (mode == "cur") { | |
T = C * ( std::pow( 1.0 + E / R, F ) - 1.0 ); | |
//cout << "mode cur" << endl; | |
} else { | |
cout << "mode not defined" << endl; | |
} | |
cout << "T " << T << endl; | |
supply.amount -= E; | |
c.balance -= T; | |
asset.amount = T; | |
asset.symbol = c.symbol; | |
return asset; | |
} | |
Asset convert(Asset from, string symbol) { | |
string sell_symbol = from.symbol; | |
string ex_symbol = supply.symbol; | |
string base_symbol = base.symbol; | |
string quote_symbol = quote.symbol; | |
if( sell_symbol != ex_symbol ) { | |
if( sell_symbol == base_symbol ) { | |
from = convert_to_exchange( base, from ); | |
} else if( sell_symbol == quote_symbol ) { | |
from = convert_to_exchange( quote, from ); | |
} else { | |
cout << "invalid sell" << endl; | |
} | |
} else { | |
if( symbol == base_symbol ) { | |
from = convert_from_exchange( base, from ); | |
} else if( symbol == quote_symbol ) { | |
from = convert_from_exchange( quote, from ); | |
} else { | |
cout << "invalid conversion" << endl; | |
} | |
} | |
if( symbol != from.symbol ) | |
return convert( from, symbol ); | |
return from; | |
} | |
}; | |
void test(string mode, string to_symbol) { | |
Bancor bc; | |
Asset asset, r_asset, r_asset_2; | |
Asset core_asset; | |
Asset acc_asset; | |
string mode_desc; | |
cout << std::setprecision(std::numeric_limits<long double>::digits10 + 1); | |
acc_asset.amount = 0.0; | |
acc_asset.symbol = to_symbol; | |
core_asset.amount = 0.0; | |
core_asset.symbol = "CORE"; | |
bc.mode = mode; | |
if (mode == "hy") { | |
mode_desc = "with fixes by @hyunwoongJi"; | |
} else if (mode == "cur") { | |
mode_desc = "with current EOSIO implementation"; | |
} | |
cout << "Test mode: " << mode_desc << ", converting between CORE <-> " << to_symbol << endl; | |
bc.report(); | |
asset.amount = 1247.49294959; | |
asset.symbol = "CORE"; | |
core_asset.amount += asset.amount; | |
cout << "converting CORE " << asset.amount << " to " << to_symbol << endl; | |
r_asset = bc.convert(asset, to_symbol); | |
acc_asset.amount += r_asset.amount; | |
cout << r_asset.amount << " " << r_asset.symbol << endl; | |
cout << "eff price ( CORE / " << to_symbol << " ): " << asset.amount / r_asset.amount << endl; | |
bc.report(); | |
asset.amount = 332.49294959; | |
asset.symbol = "CORE"; | |
core_asset.amount += asset.amount; | |
cout << "converting CORE " << asset.amount << " to " << to_symbol << endl; | |
r_asset = bc.convert(asset, to_symbol); | |
acc_asset.amount += r_asset.amount; | |
cout << r_asset.amount << " " << r_asset.symbol << endl; | |
cout << "eff price ( CORE / " << to_symbol << " ): " << asset.amount / r_asset.amount << endl; | |
bc.report(); | |
asset.amount = 672.49294959; | |
asset.symbol = "CORE"; | |
core_asset.amount += asset.amount; | |
cout << "converting CORE " << asset.amount << " to " << to_symbol << endl; | |
r_asset = bc.convert(asset, to_symbol); | |
acc_asset.amount += r_asset.amount; | |
cout << r_asset.amount << " " << r_asset.symbol << endl; | |
cout << "eff price ( CORE / " << to_symbol << " ): " << asset.amount / r_asset.amount << endl; | |
bc.report(); | |
cout << "converting " << to_symbol << " " << acc_asset.amount << " to CORE" << endl; | |
r_asset_2 = bc.convert(acc_asset, "CORE"); | |
bc.report(); | |
cout << "CORE total paid so far: " << core_asset.amount << " " << core_asset.symbol<< endl; | |
cout << "CORE total regained: " << r_asset_2.amount << " " << r_asset_2.symbol << endl; | |
cout << "CORE regained - paid: " << r_asset_2.amount - core_asset.amount << " CORE" << endl; | |
cout << "Test done: " << mode_desc << ", converting between CORE <-> " << to_symbol << endl << endl; | |
return; | |
} | |
int main() { | |
test("hy", "RAMCORE"); | |
test("cur", "RAMCORE"); | |
test("hy", "RAM"); | |
test("cur", "RAM"); | |
} |
Add two new functions into class Bancor,
long double buyRAM(long double dC) {
long double R = base.balance; // RAM
long double C = quote.balance; // EOS
long double dR; // dRAM
dR = R * (dC / (C + dC));
base.balance -= dR;
quote.balance += dC;
return dR;
}
long double sellRAM(long double dR) {
long double R = base.balance; // RAM
long double C = quote.balance; // EOS
long double dC;
dC = C * (dR / (R + dR));
quote.balance -= dC;
base.balance += dR;
return dC;
}
And add test_relay function() into main()
void test_relay() {
Bancor bc;
long double c_amount, r_amount;
long double c_amount_acc = 0.0;
long double r_amount_acc = 0.0;
c_amount = 1247.49294959;
r_amount = bc.buyRAM(c_amount);
c_amount_acc += c_amount;
r_amount_acc += r_amount;
cout << "converting CORE " << c_amount << " to RAM" << endl;
cout << "RAM: " << r_amount << endl;
c_amount = 332.49294959;
r_amount = bc.buyRAM(c_amount);
c_amount_acc += c_amount;
r_amount_acc += r_amount;
cout << "converting CORE " << c_amount << " to RAM" << endl;
cout << "RAM: " << r_amount << endl;
c_amount = 672.49294959;
r_amount = bc.buyRAM(c_amount);
c_amount_acc += c_amount;
r_amount_acc += r_amount;
cout << "converting CORE " << c_amount << " to RAM" << endl;
cout << "RAM: " << r_amount << endl;
c_amount = bc.sellRAM(r_amount_acc);
cout << "converting RAM " << r_amount_acc << " to CORE" << endl;
cout << "CORE total paid so far: " << c_amount_acc << " CORE" << endl;
cout << "CORE total regained: " << c_amount << " CORE" << endl;
cout << "CORE regained - paid: " << c_amount - c_amount_acc << " CORE" << endl;
}
int main() {
test_relay();
}
And the result is as follows:
converting CORE 1247.49294959000008 to RAM
RAM: 85620252.06687848171
converting CORE 332.4929495900000234 to RAM
RAM: 22784274.55156515296
converting CORE 672.4929495899999665 to RAM
RAM: 46036765.48410075686
converting RAM 154441292.1025443915 to CORE
CORE total paid so far: 2252.47884877000007 CORE
CORE total regained: 2252.47884877000007 CORE
CORE regained - paid: -2.220446049250313081e-16 CORE
The error is much less than the previous one.
- error of recommended implementation above : -2.220446049250313081e-16
- error of correct implementation with convert_to_exchange and convert_from_exchange : -1.389548476282698175e-10
- error of current EOSIO implementation with convert_to_exchange and convert_from_exchange : -1.218400935698582543e-10
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks @redjade.
Indeed, in current implementation the conversion between EOS and RAM verifies that the product of the connectors' reserves (EOS times RAM) is constant. This means exact agreement with Rosenfeld's paper (https://goo.gl/HXQBUr) section "multiple reserve currencies" taking S=S_0, m=2 and F_1=F_2.
This simple feature looks rather obscured in the code, leading to the following question: https://eosio.stackexchange.com/questions/408/whats-the-purpose-of-rameos-relay
See also: https://eosio.stackexchange.com/questions/317/is-there-a-math-error-in-bancor-paper