#473 erc20-support

This commit is contained in:
Vlad Dobromyslov 2023-01-31 10:48:45 +00:00 committed by serkixenos
parent cb60cbe5d1
commit 0b64f0cfcc
14 changed files with 329 additions and 83 deletions

View file

@ -1,5 +1,6 @@
#include <graphene/peerplays_sidechain/common/utils.hpp> #include <graphene/peerplays_sidechain/common/utils.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/archive/iterators/base64_from_binary.hpp> #include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/binary_from_base64.hpp> #include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/transform_width.hpp> #include <boost/archive/iterators/transform_width.hpp>
@ -47,4 +48,17 @@ std::string object_id_to_string(graphene::chain::object_id_type id) {
return object_id; return object_id;
} }
graphene::chain::object_id_type string_to_object_id(const std::string &id) {
std::vector<std::string> strs;
boost::split(strs, id, boost::is_any_of("."));
if (strs.size() != 3) {
elog("Wrong object_id format: ${id}", ("id", id));
return graphene::chain::object_id_type{};
}
auto s = boost::lexical_cast<int>(strs.at(0));
auto t = boost::lexical_cast<int>(strs.at(1));
return graphene::chain::object_id_type{(uint8_t)s, (uint8_t)t, boost::lexical_cast<uint64_t>(strs.at(2))};
}
}} // namespace graphene::peerplays_sidechain }} // namespace graphene::peerplays_sidechain

View file

@ -5,8 +5,51 @@
namespace graphene { namespace peerplays_sidechain { namespace ethereum { namespace graphene { namespace peerplays_sidechain { namespace ethereum {
//! rlp_decoder //! base_decoder
boost::multiprecision::uint256_t base_decoder::decode_uint256(const std::string &value) {
boost::multiprecision::uint256_t result = 0;
boost::multiprecision::uint256_t power(1);
uint8_t digit;
int pos = value.size() - 1;
while (pos >= 0) {
digit = 0;
if ('0' <= value[pos] && value[pos] <= '9') {
digit = value[pos] - '0';
} else if ('a' <= value[pos] && value[pos] <= 'z') {
digit = value[pos] - 'a' + 10;
}
result += digit * power;
pos--;
power *= 16;
}
return result;
}
std::string base_decoder::decode_address(const std::string &value) {
return value.substr(24, 40);
}
//! deposit_erc20_decoder
const std::string deposit_erc20_decoder::function_signature = "97feb926"; //! depositERC20(address,uint256)
fc::optional<deposit_erc20_transaction> deposit_erc20_decoder::decode(const std::string &input) {
const auto input_without_0x = remove_0x(input);
if (function_signature != input_without_0x.substr(0, 8)) {
return fc::optional<deposit_erc20_transaction>{};
}
if (input_without_0x.size() != 136) {
return fc::optional<deposit_erc20_transaction>{};
}
deposit_erc20_transaction erc_20;
erc_20.token = add_0x(base_decoder::decode_address(input_without_0x.substr(8, 64)));
erc_20.amount = base_decoder::decode_uint256(input_without_0x.substr(72, 64));
return erc_20;
}
//! rlp_decoder
namespace { namespace {
const signed char p_util_hexdigit[256] = const signed char p_util_hexdigit[256] =
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,

View file

@ -28,7 +28,7 @@ std::string base_encoder::encode_string(const std::string &value) {
//! update_owners_encoder //! update_owners_encoder
const std::string update_owners_encoder::function_signature = "23ab6adf"; //! updateOwners((address,uint256)[],string) const std::string update_owners_encoder::function_signature = "23ab6adf"; //! updateOwners((address,uint256)[],string)
std::string update_owners_encoder::encode(const std::vector<std::pair<std::string, uint16_t>> &owners_weights, const std::string &object_id) { std::string update_owners_encoder::encode(const std::vector<std::pair<std::string, uint16_t>> &owners_weights, const std::string &object_id) {
std::string data = "0x" + function_signature; std::string data = add_0x(function_signature);
data += base_encoder::encode_uint256(64); data += base_encoder::encode_uint256(64);
data += base_encoder::encode_uint256((owners_weights.size() * 2 + 3) * 32); data += base_encoder::encode_uint256((owners_weights.size() * 2 + 3) * 32);
data += base_encoder::encode_uint256(owners_weights.size()); data += base_encoder::encode_uint256(owners_weights.size());
@ -44,7 +44,7 @@ std::string update_owners_encoder::encode(const std::vector<std::pair<std::strin
//! withdrawal_encoder //! withdrawal_encoder
const std::string withdrawal_encoder::function_signature = "e088747b"; //! withdraw(address,uint256,string) const std::string withdrawal_encoder::function_signature = "e088747b"; //! withdraw(address,uint256,string)
std::string withdrawal_encoder::encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id) { std::string withdrawal_encoder::encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id) {
std::string data = "0x" + function_signature; std::string data = add_0x(function_signature);
data += base_encoder::encode_address(to); data += base_encoder::encode_address(to);
data += base_encoder::encode_uint256(amount); data += base_encoder::encode_uint256(amount);
data += base_encoder::encode_uint256(32 * 3); data += base_encoder::encode_uint256(32 * 3);
@ -53,7 +53,23 @@ std::string withdrawal_encoder::encode(const std::string &to, boost::multiprecis
return data; return data;
} }
//! withdrawal_erc20_encoder
const std::string withdrawal_erc20_encoder::function_signature = "483c0467"; //! withdrawERC20(address,address,uint256,string)
std::string withdrawal_erc20_encoder::encode(const std::string &token, const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id) {
std::string data = add_0x(function_signature);
data += base_encoder::encode_address(token);
data += base_encoder::encode_address(to);
data += base_encoder::encode_uint256(amount);
data += base_encoder::encode_uint256(32 * 4);
data += base_encoder::encode_string(object_id);
return data;
}
//! signature_encoder //! signature_encoder
const std::string update_owners_function_signature = "9d608673"; //! updateOwners((bytes,(uint8,bytes32,bytes32))[])
const std::string withdrawal_function_signature = "daac6c81"; //! withdraw((bytes,(uint8,bytes32,bytes32))[])
const std::string withdrawal_erc20_function_signature = "d2bf2866"; //! withdrawERC20((bytes,(uint8,bytes32,bytes32))[])
signature_encoder::signature_encoder(const std::string &function_hash) : signature_encoder::signature_encoder(const std::string &function_hash) :
function_signature{function_hash} { function_signature{function_hash} {
} }
@ -66,11 +82,14 @@ std::string signature_encoder::get_function_signature_from_transaction(const std
if (tr.substr(0, 8) == withdrawal_encoder::function_signature) if (tr.substr(0, 8) == withdrawal_encoder::function_signature)
return withdrawal_function_signature; return withdrawal_function_signature;
if (tr.substr(0, 8) == withdrawal_erc20_encoder::function_signature)
return withdrawal_erc20_function_signature;
return ""; return "";
} }
std::string signature_encoder::encode(const std::vector<encoded_sign_transaction> &transactions) const { std::string signature_encoder::encode(const std::vector<encoded_sign_transaction> &transactions) const {
std::string data = "0x" + function_signature; std::string data = add_0x(function_signature);
data += base_encoder::encode_uint256(32); data += base_encoder::encode_uint256(32);
data += base_encoder::encode_uint256(transactions.size()); data += base_encoder::encode_uint256(transactions.size());
size_t offset = (transactions.size()) * 32; size_t offset = (transactions.size()) * 32;

View file

@ -8,5 +8,6 @@ std::string base64_encode(const std::string &s);
std::string base64_decode(const std::string &s); std::string base64_decode(const std::string &s);
std::string object_id_to_string(graphene::chain::object_id_type id); std::string object_id_to_string(graphene::chain::object_id_type id);
graphene::chain::object_id_type string_to_object_id(const std::string &id);
}} // namespace graphene::peerplays_sidechain }} // namespace graphene::peerplays_sidechain

View file

@ -57,10 +57,16 @@ struct info_for_vin {
bool resend = false; bool resend = false;
}; };
enum class sidechain_event_type {
deposit,
withdrawal
};
struct sidechain_event_data { struct sidechain_event_data {
fc::time_point_sec timestamp; fc::time_point_sec timestamp;
uint32_t block_num; uint32_t block_num;
sidechain_type sidechain; sidechain_type sidechain;
sidechain_event_type type;
std::string sidechain_uid; std::string sidechain_uid;
std::string sidechain_transaction_id; std::string sidechain_transaction_id;
std::string sidechain_from; std::string sidechain_from;

View file

@ -1,10 +1,31 @@
#pragma once #pragma once
#include <boost/multiprecision/cpp_int.hpp>
#include <string> #include <string>
#include <vector> #include <vector>
#include <fc/optional.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum { namespace graphene { namespace peerplays_sidechain { namespace ethereum {
class base_decoder {
public:
static boost::multiprecision::uint256_t decode_uint256(const std::string &value);
static std::string decode_address(const std::string &value);
};
struct deposit_erc20_transaction {
std::string token;
boost::multiprecision::uint256_t amount;
};
class deposit_erc20_decoder {
public:
static const std::string function_signature;
static fc::optional<deposit_erc20_transaction> decode(const std::string &input);
};
class rlp_decoder { class rlp_decoder {
private: private:
enum RLP_constants { enum RLP_constants {

View file

@ -8,9 +8,6 @@
namespace graphene { namespace peerplays_sidechain { namespace ethereum { namespace graphene { namespace peerplays_sidechain { namespace ethereum {
const std::string update_owners_function_signature = "9d608673"; //! updateOwners((bytes,(uint8,bytes32,bytes32))[])
const std::string withdrawal_function_signature = "daac6c81"; //! withdraw((bytes,(uint8,bytes32,bytes32))[])
struct encoded_sign_transaction { struct encoded_sign_transaction {
std::string data; std::string data;
signature sign; signature sign;
@ -37,6 +34,13 @@ public:
static std::string encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id); static std::string encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id);
}; };
class withdrawal_erc20_encoder {
public:
static const std::string function_signature;
static std::string encode(const std::string &token, const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id);
};
class signature_encoder { class signature_encoder {
public: public:
const std::string function_signature; const std::string function_signature;

View file

@ -4,6 +4,7 @@
#include <string> #include <string>
#include <boost/bimap.hpp>
#include <boost/signals2.hpp> #include <boost/signals2.hpp>
#include <graphene/peerplays_sidechain/common/rpc_client.hpp> #include <graphene/peerplays_sidechain/common/rpc_client.hpp>
@ -52,11 +53,15 @@ public:
bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount); bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount);
virtual optional<asset> estimate_withdrawal_transaction_fee() const override; virtual optional<asset> estimate_withdrawal_transaction_fee() const override;
private:
using bimap_type = boost::bimap<std::string, std::string>;
private: private:
std::string rpc_url; std::string rpc_url;
std::string rpc_user; std::string rpc_user;
std::string rpc_password; std::string rpc_password;
std::string wallet_contract_address; std::string wallet_contract_address;
bimap_type erc20_addresses;
ethereum_rpc_client *rpc_client; ethereum_rpc_client *rpc_client;
@ -64,7 +69,6 @@ private:
ethereum::network_id_type network_id; ethereum::network_id_type network_id;
std::string create_primary_wallet_transaction(const std::vector<son_info> &son_pubkeys, const std::string &object_id); std::string create_primary_wallet_transaction(const std::vector<son_info> &son_pubkeys, const std::string &object_id);
std::string create_deposit_transaction(const son_wallet_deposit_object &swdo);
std::string create_withdrawal_transaction(const son_wallet_withdraw_object &swwo); std::string create_withdrawal_transaction(const son_wallet_withdraw_object &swwo);
std::string sign_transaction(const sidechain_transaction_object &sto); std::string sign_transaction(const sidechain_transaction_object &sto);

View file

@ -192,6 +192,8 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options(
cli.add_options()("ethereum-node-rpc-user", bpo::value<string>(), "Ethereum RPC user"); cli.add_options()("ethereum-node-rpc-user", bpo::value<string>(), "Ethereum RPC user");
cli.add_options()("ethereum-node-rpc-password", bpo::value<string>(), "Ethereum RPC password"); cli.add_options()("ethereum-node-rpc-password", bpo::value<string>(), "Ethereum RPC password");
cli.add_options()("ethereum-wallet-contract-address", bpo::value<string>(), "Ethereum wallet contract address"); cli.add_options()("ethereum-wallet-contract-address", bpo::value<string>(), "Ethereum wallet contract address");
cli.add_options()("erc-20-address", bpo::value<vector<string>>()->composing()->multitoken(),
"Tuple of [ERC-20 symbol, ERC-20 address] (may specify multiple times)");
cli.add_options()("ethereum-private-key", bpo::value<vector<string>>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", "9bedac2bd8fe2a6f6528e066c67fc8ac0622e96828d40c0e820d83c5bd2b0589")), cli.add_options()("ethereum-private-key", bpo::value<vector<string>>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", "9bedac2bd8fe2a6f6528e066c67fc8ac0622e96828d40c0e820d83c5bd2b0589")),
"Tuple of [Ethereum public key, Ethereum private key] (may specify multiple times)"); "Tuple of [Ethereum public key, Ethereum private key] (may specify multiple times)");
@ -630,6 +632,11 @@ std::map<sidechain_type, std::vector<std::string>> peerplays_sidechain_plugin_im
} }
optional<asset> peerplays_sidechain_plugin_impl::estimate_withdrawal_transaction_fee(sidechain_type sidechain) { optional<asset> peerplays_sidechain_plugin_impl::estimate_withdrawal_transaction_fee(sidechain_type sidechain) {
if (net_handlers.count(sidechain) == 0) {
wlog("No net handler for sidechain: ${sidechain}", ("sidechain", sidechain));
return optional<asset>();
}
if (!net_handlers.at(sidechain)) { if (!net_handlers.at(sidechain)) {
wlog("Net handler is null for sidechain: ${sidechain}", ("sidechain", sidechain)); wlog("Net handler is null for sidechain: ${sidechain}", ("sidechain", sidechain));
return optional<asset>(); return optional<asset>();

View file

@ -190,22 +190,25 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_
// (sed.sidechain_currency.compare("HIVE") != 0); // (sed.sidechain_currency.compare("HIVE") != 0);
#endif #endif
bool deposit_condition = (sed.peerplays_to == gpo.parameters.son_account()) && const bool deposit_condition = (sed.peerplays_to == gpo.parameters.son_account()) &&
(((sed.sidechain == sidechain_type::bitcoin) && (sed.sidechain_currency.compare("BTC") == 0)) || (sed.sidechain == sidechain) &&
((sed.sidechain == sidechain_type::ethereum) && (sed.sidechain_currency.compare("ETH") == 0)) || (sed.type == sidechain_event_type::deposit) &&
((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency.compare("HBD") == 0)) || (((sed.sidechain == sidechain_type::bitcoin) && (sed.sidechain_currency.compare("BTC") == 0)) ||
((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency.compare("HIVE") == 0)) || ((sed.sidechain == sidechain_type::ethereum) && (!sed.sidechain_currency.empty())) ||
enable_peerplays_asset_deposits); ((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency.compare("HBD") == 0)) ||
((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency.compare("HIVE") == 0)) ||
enable_peerplays_asset_deposits);
bool withdraw_condition = (sed.peerplays_to == gpo.parameters.son_account()) && (sed.sidechain == sidechain) && //! Fixme -> sidechain_type::peerplays const bool withdraw_condition = (sed.peerplays_to == gpo.parameters.son_account()) &&
((sed.sidechain_currency == object_id_to_string(gpo.parameters.btc_asset())) || (sed.sidechain == sidechain) &&
(sed.sidechain_currency == object_id_to_string(gpo.parameters.eth_asset())) || (sed.type == sidechain_event_type::withdrawal) &&
(sed.sidechain_currency == object_id_to_string(gpo.parameters.hbd_asset())) || (((sed.sidechain == sidechain_type::bitcoin) && (sed.sidechain_currency == object_id_to_string(gpo.parameters.btc_asset()))) ||
(sed.sidechain_currency == object_id_to_string(gpo.parameters.hive_asset()))); ((sed.sidechain == sidechain_type::ethereum) && (!sed.sidechain_currency.empty())) ||
((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency == object_id_to_string(gpo.parameters.hbd_asset()))) ||
((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency == object_id_to_string(gpo.parameters.hive_asset()))));
// Deposit request // Deposit request
if (deposit_condition) { if (deposit_condition) {
for (son_id_type son_id : plugin.get_sons()) { for (son_id_type son_id : plugin.get_sons()) {
if (plugin.is_active_son(sidechain, son_id)) { if (plugin.is_active_son(sidechain, son_id)) {
@ -269,7 +272,17 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_
withdraw_currency_price = database.get<asset_object>(database.get_global_properties().parameters.hive_asset()).options.core_exchange_rate; withdraw_currency_price = database.get<asset_object>(database.get_global_properties().parameters.hive_asset()).options.core_exchange_rate;
} }
if (withdraw_currency.empty()) { if (withdraw_currency.empty()) {
return; //! This is ERC-20 withdrawal
const auto asset_object_id = string_to_object_id(sed.sidechain_currency);
const auto &assets_by_id = database.get_index_type<asset_index>().indices().get<by_id>();
const auto asset_itr = assets_by_id.find(asset_object_id);
if (asset_itr == assets_by_id.end()) {
wlog("Could not find asset: ${asset_object_id}", ("asset_object_id", asset_object_id));
return;
}
withdraw_currency = asset_itr->symbol;
withdraw_currency_price = asset_itr->options.core_exchange_rate;
} }
for (son_id_type son_id : plugin.get_sons()) { for (son_id_type son_id : plugin.get_sons()) {
@ -663,9 +676,10 @@ void sidechain_net_handler::on_applied_block(const signed_block &b) {
continue; continue;
} }
bool is_tracked_asset = const bool is_tracked_asset =
((sidechain == sidechain_type::bitcoin) && (transfer_op.amount.asset_id == gpo.parameters.btc_asset())) || ((sidechain == sidechain_type::bitcoin) && (transfer_op.amount.asset_id == gpo.parameters.btc_asset())) ||
((sidechain == sidechain_type::ethereum) && (transfer_op.amount.asset_id == gpo.parameters.eth_asset())) || ((sidechain == sidechain_type::ethereum) && (transfer_op.amount.asset_id == gpo.parameters.eth_asset())) ||
(sidechain == sidechain_type::ethereum) ||
((sidechain == sidechain_type::hive) && (transfer_op.amount.asset_id == gpo.parameters.hbd_asset())) || ((sidechain == sidechain_type::hive) && (transfer_op.amount.asset_id == gpo.parameters.hbd_asset())) ||
((sidechain == sidechain_type::hive) && (transfer_op.amount.asset_id == gpo.parameters.hive_asset())); ((sidechain == sidechain_type::hive) && (transfer_op.amount.asset_id == gpo.parameters.hive_asset()));
@ -691,7 +705,8 @@ void sidechain_net_handler::on_applied_block(const signed_block &b) {
sidechain_event_data sed; sidechain_event_data sed;
sed.timestamp = database.head_block_time(); sed.timestamp = database.head_block_time();
sed.block_num = database.head_block_num(); sed.block_num = database.head_block_num();
sed.sidechain = sidechain; //! Fixme -> sidechain_type::peerplays sed.sidechain = sidechain;
sed.type = sidechain_event_type::withdrawal;
sed.sidechain_uid = sidechain_uid; sed.sidechain_uid = sidechain_uid;
sed.sidechain_transaction_id = trx.id().str(); sed.sidechain_transaction_id = trx.id().str();
sed.sidechain_from = sidechain_from; sed.sidechain_from = sidechain_from;

View file

@ -1282,6 +1282,7 @@ void sidechain_net_handler_bitcoin::handle_event(const std::string &event_data)
sed.timestamp = database.head_block_time(); sed.timestamp = database.head_block_time();
sed.block_num = database.head_block_num(); sed.block_num = database.head_block_num();
sed.sidechain = addr_itr->sidechain; sed.sidechain = addr_itr->sidechain;
sed.type = sidechain_event_type::deposit;
sed.sidechain_uid = sidechain_uid; sed.sidechain_uid = sidechain_uid;
sed.sidechain_transaction_id = v.out.hash_tx; sed.sidechain_transaction_id = v.out.hash_tx;
sed.sidechain_from = v.address; sed.sidechain_from = v.address;

View file

@ -16,6 +16,7 @@
#include <graphene/chain/sidechain_transaction_object.hpp> #include <graphene/chain/sidechain_transaction_object.hpp>
#include <graphene/chain/son_info.hpp> #include <graphene/chain/son_info.hpp>
#include <graphene/chain/son_wallet_object.hpp> #include <graphene/chain/son_wallet_object.hpp>
#include <graphene/peerplays_sidechain/ethereum/decoders.hpp>
#include <graphene/peerplays_sidechain/ethereum/encoders.hpp> #include <graphene/peerplays_sidechain/ethereum/encoders.hpp>
#include <graphene/peerplays_sidechain/ethereum/transaction.hpp> #include <graphene/peerplays_sidechain/ethereum/transaction.hpp>
#include <graphene/peerplays_sidechain/ethereum/utils.hpp> #include <graphene/peerplays_sidechain/ethereum/utils.hpp>
@ -147,6 +148,21 @@ sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidecha
wallet_contract_address = options.at("ethereum-wallet-contract-address").as<std::string>(); wallet_contract_address = options.at("ethereum-wallet-contract-address").as<std::string>();
if (options.count("erc-20-address")) {
const std::vector<std::string> symbol_addresses = options["erc-20-address"].as<std::vector<std::string>>();
for (const std::string &itr : symbol_addresses) {
auto itr_pair = graphene::app::dejsonify<std::pair<std::string, std::string>>(itr, 5);
ilog("ERC-20 symbol: ${symbol}, address: ${address}", ("symbol", itr_pair.first)("address", itr_pair.second));
if (!itr_pair.first.length() || !itr_pair.second.length()) {
FC_THROW("Invalid symbol address pair.");
}
auto address = itr_pair.second;
std::transform(address.begin(), address.end(), address.begin(), ::tolower);
erc20_addresses.insert(bimap_type::value_type{itr_pair.first, address});
}
}
if (options.count("ethereum-private-key")) { if (options.count("ethereum-private-key")) {
const std::vector<std::string> pub_priv_keys = options["ethereum-private-key"].as<std::vector<std::string>>(); const std::vector<std::string> pub_priv_keys = options["ethereum-private-key"].as<std::vector<std::string>>();
for (const std::string &itr_key_pair : pub_priv_keys) { for (const std::string &itr_key_pair : pub_priv_keys) {
@ -290,21 +306,41 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po)
const std::string sidechain_from = tx.get<std::string>("result.from"); const std::string sidechain_from = tx.get<std::string>("result.from");
const std::string sidechain_to = tx.get<std::string>("result.to"); const std::string sidechain_to = tx.get<std::string>("result.to");
const std::string value_s = tx.get<std::string>("result.value");
boost::multiprecision::uint256_t amount(value_s);
amount = amount / 100000;
amount = amount / 100000;
const fc::safe<uint64_t> sidechain_amount = amount;
std::string cmp_sidechain_to = sidechain_to; std::string cmp_sidechain_to = sidechain_to;
std::transform(cmp_sidechain_to.begin(), cmp_sidechain_to.end(), cmp_sidechain_to.begin(), ::toupper); std::transform(cmp_sidechain_to.begin(), cmp_sidechain_to.end(), cmp_sidechain_to.begin(), ::toupper);
std::string cmp_wallet_contract_address = wallet_contract_address; std::string cmp_wallet_contract_address = wallet_contract_address;
std::transform(cmp_wallet_contract_address.begin(), cmp_wallet_contract_address.end(), cmp_wallet_contract_address.begin(), ::toupper); std::transform(cmp_wallet_contract_address.begin(), cmp_wallet_contract_address.end(), cmp_wallet_contract_address.begin(), ::toupper);
process_ok = (swdo_sidechain_from == sidechain_from) && //! Check whether it is ERC-20 token deposit
std::string symbol;
boost::multiprecision::uint256_t amount;
bool error_in_deposit = false;
const auto deposit_erc_20 = ethereum::deposit_erc20_decoder::decode(tx.get<std::string>("result.input"));
if (deposit_erc_20.valid()) {
std::string cmp_token = deposit_erc_20->token;
std::transform(cmp_token.begin(), cmp_token.end(), cmp_token.begin(), ::tolower);
const auto it = erc20_addresses.right.find(cmp_token);
if (it == erc20_addresses.right.end()) {
wlog("No erc-20 token with address: ${address}", ("address", cmp_token));
error_in_deposit = true;
}
symbol = it->second;
amount = deposit_erc_20->amount;
} else {
symbol = "ETH";
const std::string value_s = tx.get<std::string>("result.value");
amount = boost::multiprecision::uint256_t{value_s};
amount = amount / 100000;
amount = amount / 100000;
}
process_ok = (!error_in_deposit) &&
(swdo_sidechain_from == sidechain_from) &&
(cmp_sidechain_to == cmp_wallet_contract_address) && (cmp_sidechain_to == cmp_wallet_contract_address) &&
(swdo_sidechain_currency == "ETH") && (swdo_sidechain_currency == symbol) &&
(swdo_sidechain_amount == sidechain_amount.value); (swdo_sidechain_amount == fc::safe<uint64_t>{amount}.value);
} }
} }
} }
@ -427,7 +463,7 @@ void sidechain_net_handler_ethereum::process_primary_wallet() {
const chain::global_property_object &gpo = database.get_global_properties(); const chain::global_property_object &gpo = database.get_global_properties();
proposal_create_operation proposal_op; proposal_create_operation proposal_op;
proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account; proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account;
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; const uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
son_wallet_update_operation swu_op; son_wallet_update_operation swu_op;
@ -489,12 +525,19 @@ bool sidechain_net_handler_ethereum::process_deposit(const son_wallet_deposit_ob
const chain::global_property_object &gpo = database.get_global_properties(); const chain::global_property_object &gpo = database.get_global_properties();
price asset_price = database.get<asset_object>(database.get_global_properties().parameters.eth_asset()).options.core_exchange_rate; const auto &assets_by_symbol = database.get_index_type<asset_index>().indices().get<by_symbol>();
asset asset_to_issue = asset(swdo.peerplays_asset.amount * asset_price.quote.amount / asset_price.base.amount, database.get_global_properties().parameters.eth_asset()); const auto asset_itr = assets_by_symbol.find(swdo.sidechain_currency);
if (asset_itr == assets_by_symbol.end()) {
wlog("Could not find asset: ${symbol}", ("symbol", swdo.sidechain_currency));
return false;
}
const price asset_price = asset_itr->options.core_exchange_rate;
const asset asset_to_issue = asset(swdo.peerplays_asset.amount * asset_price.quote.amount / asset_price.base.amount, asset_itr->get_id());
proposal_create_operation proposal_op; proposal_create_operation proposal_op;
proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account; proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account;
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; const uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
son_wallet_deposit_process_operation swdp_op; son_wallet_deposit_process_operation swdp_op;
@ -537,7 +580,7 @@ bool sidechain_net_handler_ethereum::process_withdrawal(const son_wallet_withdra
proposal_create_operation proposal_op; proposal_create_operation proposal_op;
proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account; proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account;
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; const uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
son_wallet_withdraw_process_operation swwp_op; son_wallet_withdraw_process_operation swwp_op;
@ -683,7 +726,13 @@ bool sidechain_net_handler_ethereum::settle_sidechain_transaction(const sidechai
if (sto.object_id.is<son_wallet_withdraw_id_type>()) { if (sto.object_id.is<son_wallet_withdraw_id_type>()) {
auto swwo = database.get<son_wallet_withdraw_object>(sto.object_id); auto swwo = database.get<son_wallet_withdraw_object>(sto.object_id);
settle_amount = asset(swwo.withdraw_amount, database.get_global_properties().parameters.eth_asset()); const auto &assets_by_symbol = database.get_index_type<asset_index>().indices().get<by_symbol>();
const auto asset_itr = assets_by_symbol.find(swwo.withdraw_currency);
if (asset_itr == assets_by_symbol.end()) {
wlog("Could not find asset: ${symbol}", ("symbol", swwo.withdraw_currency));
return false;
}
settle_amount = asset(swwo.withdraw_amount, asset_itr->get_id());
} }
return true; return true;
@ -712,13 +761,6 @@ optional<asset> sidechain_net_handler_ethereum::estimate_withdrawal_transaction_
return optional<asset>{}; return optional<asset>{};
} }
const auto &assets_by_symbol = database.get_index_type<asset_index>().indices().get<by_symbol>();
auto asset_itr = assets_by_symbol.find("ETH");
if (asset_itr == assets_by_symbol.end()) {
wlog("Could not find asset matching ETH");
return optional<asset>{};
}
const auto &public_key = son->sidechain_public_keys.at(sidechain); const auto &public_key = son->sidechain_public_keys.at(sidechain);
const auto data = ethereum::withdrawal_encoder::encode(public_key, 1 * 10000000000, son_wallet_withdraw_id_type{0}.operator object_id_type().operator std::string()); const auto data = ethereum::withdrawal_encoder::encode(public_key, 1 * 10000000000, son_wallet_withdraw_id_type{0}.operator object_id_type().operator std::string());
const std::string params = "[{\"from\":\"" + ethereum::add_0x(public_key) + "\", \"to\":\"" + wallet_contract_address + "\", \"data\":\"" + data + "\"}]"; const std::string params = "[{\"from\":\"" + ethereum::add_0x(public_key) + "\", \"to\":\"" + wallet_contract_address + "\", \"data\":\"" + data + "\"}]";
@ -726,7 +768,9 @@ optional<asset> sidechain_net_handler_ethereum::estimate_withdrawal_transaction_
const auto estimate_gas = ethereum::from_hex<int64_t>(rpc_client->get_estimate_gas(params)); const auto estimate_gas = ethereum::from_hex<int64_t>(rpc_client->get_estimate_gas(params));
const auto gas_price = ethereum::from_hex<int64_t>(rpc_client->get_gas_price()); const auto gas_price = ethereum::from_hex<int64_t>(rpc_client->get_gas_price());
const auto eth_gas_fee = double(estimate_gas * gas_price) / double{1000000000000000000}; const auto eth_gas_fee = double(estimate_gas * gas_price) / double{1000000000000000000};
return asset_itr->amount_from_string(std::to_string(eth_gas_fee));
const auto asset = database.get<asset_object>(database.get_global_properties().parameters.eth_asset());
return asset.amount_from_string(std::to_string(eth_gas_fee));
} }
std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(const std::vector<son_info> &son_pubkeys, const std::string &object_id) { std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(const std::vector<son_info> &son_pubkeys, const std::string &object_id) {
@ -739,12 +783,19 @@ std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(co
return ethereum::update_owners_encoder::encode(owners_weights, object_id); return ethereum::update_owners_encoder::encode(owners_weights, object_id);
} }
std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son_wallet_deposit_object &swdo) {
return "Deposit-Transaction";
}
std::string sidechain_net_handler_ethereum::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) { std::string sidechain_net_handler_ethereum::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) {
return ethereum::withdrawal_encoder::encode(swwo.withdraw_address.substr(2), swwo.withdraw_amount.value * 10000000000, swwo.id.operator std::string()); if (swwo.withdraw_currency == "ETH") {
return ethereum::withdrawal_encoder::encode(ethereum::remove_0x(swwo.withdraw_address), swwo.withdraw_amount.value * 10000000000, swwo.id.operator std::string());
} else {
const auto it = erc20_addresses.left.find(swwo.withdraw_currency);
if (it == erc20_addresses.left.end()) {
elog("No erc-20 token: ${symbol}", ("symbol", swwo.withdraw_currency));
return "";
}
return ethereum::withdrawal_erc20_encoder::encode(ethereum::remove_0x(it->second), ethereum::remove_0x(swwo.withdraw_address), swwo.withdraw_amount.value, swwo.id.operator std::string());
}
return "";
} }
std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_transaction_object &sto) { std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_transaction_object &sto) {
@ -761,10 +812,10 @@ std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_tra
} }
void sidechain_net_handler_ethereum::schedule_ethereum_listener() { void sidechain_net_handler_ethereum::schedule_ethereum_listener() {
fc::time_point now = fc::time_point::now(); const fc::time_point now = fc::time_point::now();
int64_t time_to_next = 5000; const int64_t time_to_next = 5000;
fc::time_point next_wakeup(now + fc::milliseconds(time_to_next)); const fc::time_point next_wakeup(now + fc::milliseconds(time_to_next));
_listener_task = fc::schedule([this] { _listener_task = fc::schedule([this] {
ethereum_listener_loop(); ethereum_listener_loop();
@ -776,10 +827,9 @@ void sidechain_net_handler_ethereum::ethereum_listener_loop() {
schedule_ethereum_listener(); schedule_ethereum_listener();
const auto reply = rpc_client->eth_blockNumber(); const auto reply = rpc_client->eth_blockNumber();
//std::string reply = rpc_client->eth_get_logs(wallet_contract_address);
if (!reply.empty()) { if (!reply.empty()) {
uint64_t head_block_number = ethereum::from_hex<uint64_t>(reply); const uint64_t head_block_number = ethereum::from_hex<uint64_t>(reply);
if (head_block_number != last_block_received) { if (head_block_number != last_block_received) {
//! Check that current block number is greater than last one //! Check that current block number is greater than last one
@ -814,11 +864,11 @@ void sidechain_net_handler_ethereum::handle_event(const std::string &block_numbe
size_t tx_idx = -1; size_t tx_idx = -1;
for (const auto &tx_child : block_json.get_child("result.transactions")) { for (const auto &tx_child : block_json.get_child("result.transactions")) {
boost::property_tree::ptree tx = tx_child.second; const boost::property_tree::ptree tx = tx_child.second;
tx_idx = tx_idx + 1; tx_idx = tx_idx + 1;
std::string from = tx.get<std::string>("from"); const std::string from = tx.get<std::string>("from");
std::string to = tx.get<std::string>("to"); const std::string to = tx.get<std::string>("to");
std::string cmp_to = to; std::string cmp_to = to;
std::transform(cmp_to.begin(), cmp_to.end(), cmp_to.begin(), ::toupper); std::transform(cmp_to.begin(), cmp_to.end(), cmp_to.begin(), ::toupper);
@ -827,10 +877,35 @@ void sidechain_net_handler_ethereum::handle_event(const std::string &block_numbe
if (cmp_to == cmp_wallet_contract_address) { if (cmp_to == cmp_wallet_contract_address) {
std::string value_s = tx.get<std::string>("value"); //! Check whether it is ERC-20 token deposit
boost::multiprecision::uint256_t amount(value_s); std::string symbol;
amount = amount / 100000; boost::multiprecision::uint256_t amount;
amount = amount / 100000; const auto deposit_erc_20 = ethereum::deposit_erc20_decoder::decode(tx.get<std::string>("input"));
if (deposit_erc_20.valid()) {
std::string cmp_token = deposit_erc_20->token;
std::transform(cmp_token.begin(), cmp_token.end(), cmp_token.begin(), ::tolower);
const auto it = erc20_addresses.right.find(cmp_token);
if (it == erc20_addresses.right.end()) {
wlog("No erc-20 token with address: ${address}", ("address", cmp_token));
continue;
}
symbol = it->second;
amount = deposit_erc_20->amount;
} else {
symbol = "ETH";
const std::string value_s = tx.get<std::string>("value");
amount = boost::multiprecision::uint256_t{value_s};
amount = amount / 100000;
amount = amount / 100000;
}
const auto &assets_by_symbol = database.get_index_type<asset_index>().indices().get<by_symbol>();
const auto asset_itr = assets_by_symbol.find(symbol);
if (asset_itr == assets_by_symbol.end()) {
wlog("Could not find asset: ${symbol}", ("symbol", symbol));
continue;
}
const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>().indices().get<by_sidechain_and_deposit_address_and_expires>(); const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>().indices().get<by_sidechain_and_deposit_address_and_expires>();
const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sidechain, from, time_point_sec::maximum())); const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sidechain, from, time_point_sec::maximum()));
@ -841,22 +916,22 @@ void sidechain_net_handler_ethereum::handle_event(const std::string &block_numbe
std::stringstream ss; std::stringstream ss;
ss << "ethereum" ss << "ethereum"
<< "-" << tx.get<std::string>("hash") << "-" << tx_idx; << "-" << tx.get<std::string>("hash") << "-" << tx_idx;
std::string sidechain_uid = ss.str();
sidechain_event_data sed; sidechain_event_data sed;
sed.timestamp = database.head_block_time(); sed.timestamp = database.head_block_time();
sed.block_num = database.head_block_num(); sed.block_num = database.head_block_num();
sed.sidechain = sidechain; sed.sidechain = sidechain;
sed.sidechain_uid = sidechain_uid; sed.type = sidechain_event_type::deposit;
sed.sidechain_uid = ss.str();
sed.sidechain_transaction_id = tx.get<std::string>("hash"); sed.sidechain_transaction_id = tx.get<std::string>("hash");
sed.sidechain_from = from; sed.sidechain_from = from;
sed.sidechain_to = to; sed.sidechain_to = to;
sed.sidechain_currency = "ETH"; sed.sidechain_currency = symbol;
sed.sidechain_amount = amount; sed.sidechain_amount = amount;
sed.peerplays_from = addr_itr->sidechain_address_account; sed.peerplays_from = addr_itr->sidechain_address_account;
sed.peerplays_to = database.get_global_properties().parameters.son_account(); sed.peerplays_to = database.get_global_properties().parameters.son_account();
price eth_price = database.get<asset_object>(database.get_global_properties().parameters.eth_asset()).options.core_exchange_rate; const price price = asset_itr->options.core_exchange_rate;
sed.peerplays_asset = asset(sed.sidechain_amount * eth_price.base.amount / eth_price.quote.amount); sed.peerplays_asset = asset(sed.sidechain_amount * price.base.amount / price.quote.amount);
add_to_son_listener_log("TRX : " + sed.sidechain_transaction_id); add_to_son_listener_log("TRX : " + sed.sidechain_transaction_id);

View file

@ -950,6 +950,7 @@ void sidechain_net_handler_hive::handle_event(const std::string &event_data) {
sed.timestamp = database.head_block_time(); sed.timestamp = database.head_block_time();
sed.block_num = database.head_block_num(); sed.block_num = database.head_block_num();
sed.sidechain = sidechain; sed.sidechain = sidechain;
sed.type = sidechain_event_type::deposit;
sed.sidechain_uid = sidechain_uid; sed.sidechain_uid = sidechain_uid;
sed.sidechain_transaction_id = transaction_id; sed.sidechain_transaction_id = transaction_id;
sed.sidechain_from = from; sed.sidechain_from = from;

View file

@ -2,6 +2,7 @@
#include <fc/crypto/hex.hpp> #include <fc/crypto/hex.hpp>
#include <graphene/peerplays_sidechain/ethereum/encoders.hpp> #include <graphene/peerplays_sidechain/ethereum/encoders.hpp>
#include <graphene/peerplays_sidechain/ethereum/decoders.hpp>
#include <graphene/peerplays_sidechain/ethereum/transaction.hpp> #include <graphene/peerplays_sidechain/ethereum/transaction.hpp>
using namespace graphene::peerplays_sidechain::ethereum; using namespace graphene::peerplays_sidechain::ethereum;
@ -9,22 +10,43 @@ using namespace graphene::peerplays_sidechain::ethereum;
BOOST_AUTO_TEST_SUITE(ethereum_transaction_tests) BOOST_AUTO_TEST_SUITE(ethereum_transaction_tests)
BOOST_AUTO_TEST_CASE(withdrawal_encoder_test) { BOOST_AUTO_TEST_CASE(withdrawal_encoder_test) {
const auto tx = withdrawal_encoder::encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.0"); const auto tx = withdrawal_encoder::encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.39.0");
BOOST_CHECK_EQUAL(tx, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E300000000000000000000000000000000000000000000000000000"); BOOST_CHECK_EQUAL(tx, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33392E300000000000000000000000000000000000000000000000000000");
const auto tx1 = withdrawal_encoder::encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.1"); const auto tx1 = withdrawal_encoder::encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.39.1");
BOOST_CHECK_EQUAL(tx1, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000"); BOOST_CHECK_EQUAL(tx1, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33392E310000000000000000000000000000000000000000000000000000");
} }
BOOST_AUTO_TEST_CASE(withdrawal_signature_encoder_test) { BOOST_AUTO_TEST_CASE(withdrawal_signature_encoder_test) {
const signature_encoder encoder{withdrawal_function_signature};
encoded_sign_transaction transaction; encoded_sign_transaction transaction;
transaction.data = "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E300000000000000000000000000000000000000000000000000000"; transaction.data = "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33392E300000000000000000000000000000000000000000000000000000";
transaction.sign = sign_hash(keccak_hash(transaction.data), "0x21", "eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060" ); transaction.sign = sign_hash(keccak_hash(transaction.data), "0x21", "eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060" );
const auto function_signature = signature_encoder::get_function_signature_from_transaction(transaction.data);
BOOST_REQUIRE_EQUAL(function_signature.empty(), false);
const signature_encoder encoder{function_signature};
const auto tx = encoder.encode({transaction}); const auto tx = encoder.encode({transaction});
BOOST_CHECK_EQUAL(tx, "0xdaac6c8100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000065c4622d2ff2b2d89c5c6f8225ab0f979bc69d4fcd4fd47db757b66fb8a39e2bc5522be5d101aa11e66da78db973f136b323be10bd107ff0b648f06b4c71ef2a4f00000000000000000000000000000000000000000000000000000000000000a4e088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); BOOST_CHECK_EQUAL(tx, "0xdaac6c810000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000006689c3a93d7059430d19ff952900dfada310c0dcced9ed046c335f886091c7e50c1a01016a488777b41a1815ca01a7d809ed47c36dcb0d5f86a43b079ce0d04afe00000000000000000000000000000000000000000000000000000000000000a4e088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33392E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
}
BOOST_AUTO_TEST_CASE(withdrawal_erc20_encoder_test) {
const auto tx = withdrawal_erc20_encoder::encode("cc806da9df9d634b5dac0aa36dca1e7780e42C60", "5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10, "1.39.0");
BOOST_CHECK_EQUAL(tx, "0x483c0467000000000000000000000000cc806da9df9d634b5dac0aa36dca1e7780e42C600000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc12000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000006312E33392E300000000000000000000000000000000000000000000000000000");
const auto tx1 = withdrawal_erc20_encoder::encode("cc806da9df9d634b5dac0aa36dca1e7780e42C60", "5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10, "1.39.1");
BOOST_CHECK_EQUAL(tx1, "0x483c0467000000000000000000000000cc806da9df9d634b5dac0aa36dca1e7780e42C600000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc12000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000006312E33392E310000000000000000000000000000000000000000000000000000");
}
BOOST_AUTO_TEST_CASE(withdrawal_erc20_signature_encoder_test) {
encoded_sign_transaction transaction;
transaction.data = "0x483c0467000000000000000000000000cc806da9df9d634b5dac0aa36dca1e7780e42C600000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc12000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000006312E33392E300000000000000000000000000000000000000000000000000000";
transaction.sign = sign_hash(keccak_hash(transaction.data), "0x21", "eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060" );
const auto function_signature = signature_encoder::get_function_signature_from_transaction(transaction.data);
BOOST_REQUIRE_EQUAL(function_signature.empty(), false);
const signature_encoder encoder{function_signature};
const auto tx = encoder.encode({transaction});
BOOST_CHECK_EQUAL(tx, "0xd2bf286600000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000066f51f7732435016936f0e21aa3c290023ea96ddbc369a957aca28a865cb5004a46675855fccd4bd5a283e1ff61aa60ca9b8b63664e770689e5cfc1a0c6bbdc79a00000000000000000000000000000000000000000000000000000000000000c4483c0467000000000000000000000000cc806da9df9d634b5dac0aa36dca1e7780e42C600000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc12000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000006312E33392E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
} }
BOOST_AUTO_TEST_CASE(update_owners_encoder_test) { BOOST_AUTO_TEST_CASE(update_owners_encoder_test) {
@ -32,23 +54,36 @@ BOOST_AUTO_TEST_CASE(update_owners_encoder_test) {
owners_weights.emplace_back("5FbBb31BE52608D2F52247E8400B7fCaA9E0bC12", 1); owners_weights.emplace_back("5FbBb31BE52608D2F52247E8400B7fCaA9E0bC12", 1);
owners_weights.emplace_back("76ce31bd03f601c3fc13732def921c5bac282676", 1); owners_weights.emplace_back("76ce31bd03f601c3fc13732def921c5bac282676", 1);
const auto tx = update_owners_encoder::encode(owners_weights, "1.35.0"); const auto tx = update_owners_encoder::encode(owners_weights, "1.39.0");
BOOST_CHECK_EQUAL(tx, "0x23ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E300000000000000000000000000000000000000000000000000000"); BOOST_CHECK_EQUAL(tx, "0x23ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33392E300000000000000000000000000000000000000000000000000000");
owners_weights.emplace_back("09ee460834498a4ee361beb819470061b7381b49", 1); owners_weights.emplace_back("09ee460834498a4ee361beb819470061b7381b49", 1);
const auto tx1 = update_owners_encoder::encode(owners_weights, "1.36.1"); const auto tx1 = update_owners_encoder::encode(owners_weights, "1.39.1");
BOOST_CHECK_EQUAL(tx1, "0x23ab6adf0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000030000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac282676000000000000000000000000000000000000000000000000000000000000000100000000000000000000000009ee460834498a4ee361beb819470061b7381b4900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000"); BOOST_CHECK_EQUAL(tx1, "0x23ab6adf0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000030000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac282676000000000000000000000000000000000000000000000000000000000000000100000000000000000000000009ee460834498a4ee361beb819470061b7381b4900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33392E310000000000000000000000000000000000000000000000000000");
} }
BOOST_AUTO_TEST_CASE(update_owners_signature_encoder_test) { BOOST_AUTO_TEST_CASE(update_owners_signature_encoder_test) {
const signature_encoder encoder{update_owners_function_signature};
encoded_sign_transaction transaction; encoded_sign_transaction transaction;
transaction.data = "0x23ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E300000000000000000000000000000000000000000000000000000"; transaction.data = "0x23ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33392E300000000000000000000000000000000000000000000000000000";
transaction.sign = sign_hash(keccak_hash(transaction.data), "0x21", "eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060" ); transaction.sign = sign_hash(keccak_hash(transaction.data), "0x21", "eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060" );
const auto function_signature = signature_encoder::get_function_signature_from_transaction(transaction.data);
BOOST_REQUIRE_EQUAL(function_signature.empty(), false);
const signature_encoder encoder{function_signature};
const auto tx = encoder.encode({transaction}); const auto tx = encoder.encode({transaction});
BOOST_CHECK_EQUAL(tx, "0x9d6086730000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000006698877eafa525c1a55f6b5e0a7187dfae484c97d9f77c4421a00276a9408a3e713d24402b44c05a883142fcffa84e1a802be37c17bb360f6f4810eb0415c8bbfd000000000000000000000000000000000000000000000000000000000000012423ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); BOOST_CHECK_EQUAL(tx, "0x9d608673000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000667121da3c6ab5054b1a77cac477f24e7ce7bfcb5e3a857cfcaf48e67fc8f003ac38dfa8821525383608a68c9f215f9a2a232e192ae80079cd2f31b0e01caa6e1d000000000000000000000000000000000000000000000000000000000000012423ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33392E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
}
BOOST_AUTO_TEST_CASE(deposit_erc20_decoder_test) {
const auto erc_20_1 = deposit_erc20_decoder::decode("0x97feb926000000000000000000000000cc806da9df9d634b5dac0aa36dca1e7780e42c600000000000000000000000000000000000000000000000000000000000000064");
BOOST_REQUIRE_EQUAL(erc_20_1.valid(), true);
BOOST_CHECK_EQUAL(erc_20_1->token, "0xcc806da9df9d634b5dac0aa36dca1e7780e42c60");
BOOST_CHECK_EQUAL(erc_20_1->amount, 100);
const auto erc_20_2 = deposit_erc20_decoder::decode("0x97feb926000000000000000000000000cc806da9df9d634b5dac0aa36dca1e7780e42c600000000000000000000000000000000000000000000000006400000000000000");
BOOST_REQUIRE_EQUAL(erc_20_2.valid(), true);
BOOST_CHECK_EQUAL(erc_20_2->token, "0xcc806da9df9d634b5dac0aa36dca1e7780e42c60");
BOOST_CHECK_EQUAL(erc_20_2->amount, 7205759403792793600);
} }
BOOST_AUTO_TEST_CASE(raw_transaction_serialization_test) { BOOST_AUTO_TEST_CASE(raw_transaction_serialization_test) {