forked from lthn/blockchain
multiple fixes over ionic_swap proposal
This commit is contained in:
parent
aa8d3207a4
commit
4acb2bae03
7 changed files with 175 additions and 64 deletions
|
|
@ -406,7 +406,7 @@ namespace currency
|
|||
tx_destination_entry de = AUTO_VAL_INIT(de);
|
||||
de.addr.push_back(miner_address);
|
||||
de.amount = a;
|
||||
de.explicit_native_asset_id = true; // don't use asset id blinding as it's obvious which asset it is
|
||||
de.flags |= tx_destination_entry_flags::tdef_explicit_native_asset_id; // don't use asset id blinding as it's obvious which asset it is
|
||||
if (pe.stake_unlock_time && pe.stake_unlock_time > height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW)
|
||||
{
|
||||
//this means that block is creating after hardfork_1 and unlock_time is needed to set for every destination separately
|
||||
|
|
@ -421,7 +421,7 @@ namespace currency
|
|||
if (pe.stake_unlock_time && pe.stake_unlock_time > height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW)
|
||||
stake_lock_time = pe.stake_unlock_time;
|
||||
destinations.push_back(tx_destination_entry(pe.amount, stakeholder_address, stake_lock_time));
|
||||
destinations.back().explicit_native_asset_id = true; // don't use asset id blinding as it's obvious which asset it is
|
||||
destinations.back().flags |= tx_destination_entry_flags::tdef_explicit_native_asset_id; // don't use asset id blinding as it's obvious which asset it is
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_MES(destinations.size() <= CURRENCY_TX_MAX_ALLOWED_OUTS || height == 0, false, "Too many outs (" << destinations.size() << ")! Miner tx can't be constructed.");
|
||||
|
|
@ -1143,8 +1143,8 @@ namespace currency
|
|||
blinded_asset_id = crypto::point_t(de.asset_id) + asset_blinding_mask * crypto::c_point_X;
|
||||
out.blinded_asset_id = (crypto::c_scalar_1div8 * blinded_asset_id).to_public_key(); // T = 1/8 * (H_asset + s * X)
|
||||
|
||||
CHECK_AND_ASSERT_MES(!de.explicit_native_asset_id || de.asset_id == currency::native_coin_asset_id, false, "explicit_native_asset_id may be used only with native asset id");
|
||||
asset_blinding_mask = de.explicit_native_asset_id ? 0 : crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_ASSET_BLINDING_MASK, h); // f = Hs(domain_sep, d, i)
|
||||
CHECK_AND_ASSERT_MES(!de.flags & tx_destination_entry_flags::tdef_explicit_native_asset_id || de.asset_id == currency::native_coin_asset_id, false, "explicit_native_asset_id may be used only with native asset id");
|
||||
asset_blinding_mask = de.flags & tx_destination_entry_flags::tdef_explicit_native_asset_id ? 0 : crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_ASSET_BLINDING_MASK, h); // f = Hs(domain_sep, d, i)
|
||||
amount_commitment = de.amount * blinded_asset_id + amount_blinding_mask * crypto::c_point_G;
|
||||
out.amount_commitment = (crypto::c_scalar_1div8 * amount_commitment).to_public_key(); // E = 1/8 * e * T + 1/8 * y * G
|
||||
|
||||
|
|
@ -1163,8 +1163,8 @@ namespace currency
|
|||
crypto::scalar_t amount_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_AMOUNT_MASK, h);
|
||||
out.encrypted_amount = de.amount ^ amount_mask.m_u64[0];
|
||||
|
||||
CHECK_AND_ASSERT_MES(!de.explicit_native_asset_id || de.asset_id == currency::native_coin_asset_id, false, "explicit_native_asset_id may be used only with native asset id");
|
||||
asset_blinding_mask = de.explicit_native_asset_id ? 0 : crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_ASSET_BLINDING_MASK, h); // f = Hs(domain_sep, d, i)
|
||||
CHECK_AND_ASSERT_MES(!de.flags & tx_destination_entry_flags::tdef_explicit_native_asset_id || de.asset_id == currency::native_coin_asset_id, false, "explicit_native_asset_id may be used only with native asset id");
|
||||
asset_blinding_mask = de.flags & tx_destination_entry_flags::tdef_explicit_native_asset_id ? 0 : crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_ASSET_BLINDING_MASK, h); // f = Hs(domain_sep, d, i)
|
||||
blinded_asset_id = crypto::point_t(de.asset_id) + asset_blinding_mask * crypto::c_point_X;
|
||||
out.blinded_asset_id = (crypto::c_scalar_1div8 * blinded_asset_id).to_public_key(); // T = 1/8 * (H_asset + s * X)
|
||||
|
||||
|
|
@ -2271,7 +2271,7 @@ namespace currency
|
|||
{
|
||||
tx_destination_entry& dst_entr = shuffled_dsts[j];
|
||||
if (all_inputs_are_obviously_native_coins && gen_context.ao_asset_id == currency::null_pkey)
|
||||
dst_entr.explicit_native_asset_id = true; // all inputs are obviously native coins -- all outputs must have explicit asset ids (unless there's an asset emission)
|
||||
dst_entr.flags |= tx_destination_entry_flags::tdef_explicit_native_asset_id; // all inputs are obviously native coins -- all outputs must have explicit asset ids (unless there's an asset emission)
|
||||
|
||||
CHECK_AND_ASSERT_MES(dst_entr.amount > 0, false, "Destination with wrong amount: " << dst_entr.amount); // <<-- TODO @#@# consider removing this check
|
||||
r = construct_tx_out(dst_entr, txkey.sec, output_index, tx, deriv_cache, sender_account_keys,
|
||||
|
|
@ -2317,8 +2317,16 @@ namespace currency
|
|||
std::sort(tx.vin.begin() + input_starter_index, tx.vin.end(), less_txin_v);
|
||||
|
||||
// add explicit fee info
|
||||
r = add_tx_fee_amount_to_extra(tx, native_coins_input_sum - native_coins_output_sum);
|
||||
CHECK_AND_ASSERT_MES(r, false, "add_tx_fee_amount_to_extra failed");
|
||||
uint64_t fee_to_declare = native_coins_input_sum - native_coins_output_sum;
|
||||
if (flags & TX_FLAG_SIGNATURE_MODE_SEPARATE)
|
||||
{
|
||||
fee_to_declare = ftp.mode_separate_fee;
|
||||
}
|
||||
if (fee_to_declare)
|
||||
{
|
||||
r = add_tx_fee_amount_to_extra(tx, fee_to_declare);
|
||||
CHECK_AND_ASSERT_MES(r, false, "add_tx_fee_amount_to_extra failed");
|
||||
}
|
||||
}
|
||||
|
||||
// attachments container should be sealed by now
|
||||
|
|
@ -2357,10 +2365,9 @@ namespace currency
|
|||
for (size_t i_ = 0; i_ != sources.size(); i_++)
|
||||
{
|
||||
size_t i_mapped = inputs_mapping[i_];
|
||||
|
||||
const tx_source_entry& source_entry = sources[i_mapped];
|
||||
crypto::hash tx_hash_for_signature = prepare_prefix_hash_for_sign(tx, i_ + input_starter_index, tx_prefix_hash);
|
||||
CHECK_AND_ASSERT_MES(tx_hash_for_signature != null_hash, false, "prepare_prefix_hash_for_sign failed");
|
||||
CHECK_AND_ASSERT_MES(tx_hash_for_signature != null_hash, false, "prepare_prefix_hash_for_sign failed");
|
||||
std::stringstream ss_ring_s;
|
||||
|
||||
if (source_entry.is_zc())
|
||||
|
|
@ -2369,6 +2376,7 @@ namespace currency
|
|||
// blinding_masks_sum is supposed to be sum(mask of all tx output) - sum(masks of all pseudo out commitments)
|
||||
r = generate_ZC_sig(tx_hash_for_signature, i_ + input_starter_index, source_entry, in_contexts[i_mapped], sender_account_keys, flags, gen_context, tx, i_ + 1 == sources.size());
|
||||
CHECK_AND_ASSERT_MES(r, false, "generate_ZC_sigs failed");
|
||||
gen_context.input_amounts[i_ + input_starter_index] = source_entry.amount;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ namespace currency
|
|||
|
||||
struct finalize_tx_param
|
||||
{
|
||||
|
||||
uint64_t unlock_time;
|
||||
std::vector<currency::extra_v> extra;
|
||||
std::vector<currency::attachment_v> attachments;
|
||||
|
|
@ -156,6 +157,7 @@ namespace currency
|
|||
uint64_t expiration_time;
|
||||
crypto::public_key spend_pub_key; // only for validations
|
||||
uint64_t tx_version;
|
||||
uint64_t mode_separate_fee = 0;
|
||||
|
||||
tx_generation_context gen_context{}; // solely for consolidated txs
|
||||
|
||||
|
|
@ -174,6 +176,7 @@ namespace currency
|
|||
FIELD(expiration_time)
|
||||
FIELD(spend_pub_key)
|
||||
FIELD(tx_version)
|
||||
FIELD(mode_separate_fee)
|
||||
if (flags & TX_FLAG_SIGNATURE_MODE_SEPARATE)
|
||||
FIELD(gen_context);
|
||||
END_SERIALIZE()
|
||||
|
|
|
|||
|
|
@ -94,6 +94,13 @@ namespace currency
|
|||
};
|
||||
|
||||
|
||||
enum tx_destination_entry_flags
|
||||
{
|
||||
tdef_none = 0,
|
||||
tdef_explicit_native_asset_id = 0x0001,
|
||||
tdef_explicit_amount_to_provide = 0x0002
|
||||
};
|
||||
|
||||
struct tx_destination_entry
|
||||
{
|
||||
uint64_t amount = 0; // money
|
||||
|
|
@ -103,7 +110,7 @@ namespace currency
|
|||
uint64_t unlock_time = 0;
|
||||
destination_option_htlc_out htlc_options; // htlc options
|
||||
crypto::public_key asset_id = currency::native_coin_asset_id; // not blinded, not premultiplied
|
||||
bool explicit_native_asset_id = false;
|
||||
uint64_t flags = 0; // set of flags (see tx_destination_entry_flags)
|
||||
|
||||
tx_destination_entry() = default;
|
||||
tx_destination_entry(uint64_t a, const account_public_address& ad) : amount(a), addr(1, ad) {}
|
||||
|
|
@ -123,7 +130,7 @@ namespace currency
|
|||
FIELD(unlock_time)
|
||||
FIELD(htlc_options)
|
||||
FIELD(asset_id)
|
||||
FIELD(explicit_native_asset_id)
|
||||
FIELD(flags)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
//---------------------------------------------------------------
|
||||
|
|
@ -218,6 +225,7 @@ namespace currency
|
|||
asset_id_blinding_masks.resize(outs_count);
|
||||
amounts.resize(outs_count);
|
||||
amount_blinding_masks.resize(outs_count);
|
||||
input_amounts.resize(zc_ins_count);
|
||||
}
|
||||
|
||||
// TODO @#@# reconsider this check -- sowle
|
||||
|
|
@ -245,6 +253,7 @@ namespace currency
|
|||
std::vector<crypto::point_t> pseudo_outs_blinded_asset_ids; // generate_asset_surjection_proof
|
||||
crypto::scalar_vec_t pseudo_outs_plus_real_out_blinding_masks; // r_pi + r'_j // generate_asset_surjection_proof
|
||||
std::vector<crypto::point_t> real_zc_ins_asset_ids; // H_i // generate_asset_surjection_proof
|
||||
std::vector<uint64_t> input_amounts; // all inputs, including non ZC
|
||||
|
||||
// common data: inputs
|
||||
crypto::point_t pseudo_out_amount_commitments_sum = crypto::c_point_0; // generate_tx_balance_proof generate_ZC_sig
|
||||
|
|
@ -273,6 +282,7 @@ namespace currency
|
|||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(pseudo_outs_blinded_asset_ids)
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(pseudo_outs_plus_real_out_blinding_masks)
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(real_zc_ins_asset_ids)
|
||||
KV_SERIALIZE(input_amounts)
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(pseudo_out_amount_commitments_sum)
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(pseudo_out_amount_blinding_masks_sum)
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(real_in_asset_id_blinding_mask_x_amount_sum)
|
||||
|
|
@ -298,6 +308,7 @@ namespace currency
|
|||
FIELD(pseudo_outs_blinded_asset_ids)
|
||||
FIELD((std::vector<crypto::scalar_t>&)(pseudo_outs_plus_real_out_blinding_masks))
|
||||
FIELD(real_zc_ins_asset_ids)
|
||||
FIELD(input_amounts)
|
||||
FIELD(pseudo_out_amount_commitments_sum)
|
||||
FIELD(pseudo_out_amount_blinding_masks_sum)
|
||||
FIELD(real_in_asset_id_blinding_mask_x_amount_sum)
|
||||
|
|
|
|||
|
|
@ -5011,34 +5011,38 @@ bool wallet2::build_ionic_swap_template(const wallet_public::ionic_swap_proposal
|
|||
construct_tx_param ctp = get_default_construct_tx_param();
|
||||
|
||||
ctp.fake_outputs_count = proposal_detais.mixins;
|
||||
ctp.fee = 0;
|
||||
ctp.fee = proposal_detais.fee_paid_by_a;
|
||||
ctp.flags = TX_FLAG_SIGNATURE_MODE_SEPARATE;
|
||||
ctp.mark_tx_as_complete = false;
|
||||
ctp.crypt_address = destination_addr;
|
||||
|
||||
etc_tx_details_expiration_time t = AUTO_VAL_INIT(t);
|
||||
t.v = proposal_detais.expiration_time;
|
||||
ctp.extra.push_back(t);
|
||||
|
||||
ctp.dsts.resize(proposal_detais.from.size() + proposal_detais.to.size());
|
||||
ctp.dsts.resize(proposal_detais.to_bob.size() + proposal_detais.to_alice.size());
|
||||
size_t i = 0;
|
||||
// Here is an proposed for exchange funds
|
||||
for (; i != proposal_detais.from.size(); i++)
|
||||
for (; i != proposal_detais.to_bob.size(); i++)
|
||||
{
|
||||
ctp.dsts[i].amount = proposal_detais.from[i].amount;
|
||||
ctp.dsts[i].amount_to_provide = proposal_detais.from[i].amount;
|
||||
ctp.dsts[i].amount = proposal_detais.to_bob[i].amount;
|
||||
ctp.dsts[i].amount_to_provide = proposal_detais.to_bob[i].amount;
|
||||
ctp.dsts[i].flags |= tx_destination_entry_flags::tdef_explicit_amount_to_provide;
|
||||
ctp.dsts[i].addr.push_back(destination_addr);
|
||||
ctp.dsts[i].asset_id = proposal_detais.from[i].asset_id;
|
||||
ctp.dsts[i].asset_id = proposal_detais.to_bob[i].asset_id;
|
||||
}
|
||||
// Here is an expected in return funds
|
||||
for (size_t j = 0; j != proposal_detais.to.size(); j++, i++)
|
||||
for (size_t j = 0; j != proposal_detais.to_alice.size(); j++, i++)
|
||||
{
|
||||
ctp.dsts[i].amount = proposal_detais.to[j].amount;
|
||||
ctp.dsts[i].amount = proposal_detais.to_alice[j].amount;
|
||||
ctp.dsts[i].amount_to_provide = 0;
|
||||
ctp.dsts[i].flags |= tx_destination_entry_flags::tdef_explicit_amount_to_provide;
|
||||
ctp.dsts[i].addr.push_back(m_account.get_public_address());
|
||||
ctp.dsts[i].asset_id = proposal_detais.to[j].asset_id;
|
||||
ctp.dsts[i].asset_id = proposal_detais.to_alice[j].asset_id;
|
||||
}
|
||||
|
||||
currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp);
|
||||
ftp.mode_separate_fee = ctp.fee;
|
||||
ftp.tx_version = this->get_current_tx_version();
|
||||
prepare_transaction(ctp, ftp);
|
||||
|
||||
|
|
@ -5053,7 +5057,7 @@ bool wallet2::build_ionic_swap_template(const wallet_public::ionic_swap_proposal
|
|||
ispc.gen_context = finalize_result.ftp.gen_context;
|
||||
ispc.one_time_skey = finalize_result.one_time_key;
|
||||
std::string proposal_context_blob = t_serializable_object_to_blob(ispc);
|
||||
proposal.encrypted_context = crypto::chacha_crypt(proposal_context_blob, finalize_result.derivation);
|
||||
proposal.encrypted_context = crypto::chacha_crypt(static_cast<const std::string&>(proposal_context_blob), finalize_result.derivation);
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
|
@ -5093,53 +5097,115 @@ bool wallet2::get_ionic_swap_proposal_info(const wallet_public::ionic_swap_propo
|
|||
r = validate_tx_output_details_againt_tx_generation_context(tx, ionic_context.gen_context, ionic_context.one_time_skey);
|
||||
THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "Failed to validate decrypted ionic_context");
|
||||
|
||||
std::unordered_map<crypto::public_key, uint64_t> ammounts_to;
|
||||
std::unordered_map<crypto::public_key, uint64_t> ammounts_from;
|
||||
std::vector<bool> third_party_outs;
|
||||
size_t i = 0;
|
||||
std::unordered_map<crypto::public_key, uint64_t> amounts_provided_by_a;
|
||||
|
||||
std::unordered_map<crypto::public_key, uint64_t> ammounts_to_a; //amounts to Alice (the one who created proposal), should be NOT funded
|
||||
std::unordered_map<crypto::public_key, uint64_t> ammounts_to_b; //amounts to Bob (the one who received proposal), should BE funded
|
||||
std::vector<bool> bob_outs;
|
||||
bob_outs.resize(proposal.tx_template.vout.size());
|
||||
|
||||
for (const auto& o : outs)
|
||||
{
|
||||
THROW_IF_FALSE_WALLET_INT_ERR_EX(ionic_context.gen_context.asset_ids.size() > i, "Tx gen context has mismatch with tx(asset_ids) ");
|
||||
THROW_IF_FALSE_WALLET_INT_ERR_EX(ionic_context.gen_context.asset_ids[i].to_public_key() == o.asset_id, "Tx gen context has mismatch with tx(asset_id != asset_id) ");
|
||||
THROW_IF_FALSE_WALLET_INT_ERR_EX(ionic_context.gen_context.amounts[i].m_u64[0] == o.amount, "Tx gen context has mismatch with tx(amount != amount)");
|
||||
THROW_IF_FALSE_WALLET_INT_ERR_EX(ionic_context.gen_context.asset_ids.size() > o.index, "Tx gen context has mismatch with tx(asset_ids) ");
|
||||
THROW_IF_FALSE_WALLET_INT_ERR_EX(ionic_context.gen_context.asset_ids[o.index].to_public_key() == o.asset_id, "Tx gen context has mismatch with tx(asset_id != asset_id) ");
|
||||
THROW_IF_FALSE_WALLET_INT_ERR_EX(ionic_context.gen_context.amounts[o.index].m_u64[0] == o.amount, "Tx gen context has mismatch with tx(amount != amount)");
|
||||
|
||||
ammounts_to[o.asset_id] += o.amount;
|
||||
third_party_outs[i] = false;
|
||||
i++;
|
||||
ammounts_to_b[o.asset_id] += o.amount;
|
||||
bob_outs[o.index] = true;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
//validate outputs against decrypted tx generation context
|
||||
for (i = 0; i != tx.vout.size(); i++)
|
||||
{
|
||||
|
||||
if (!third_party_outs[i])
|
||||
if (bob_outs[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
crypto::public_key asset_id = ionic_context.gen_context.asset_ids[i].to_public_key();
|
||||
uint64_t amount = ionic_context.gen_context.amounts[i].m_u64[0];
|
||||
ammounts_from[asset_id] += amount;
|
||||
ammounts_to_a[asset_id] += amount;
|
||||
}
|
||||
|
||||
for (const auto& a : ammounts_to)
|
||||
proposal_info.to.push_back(view::asset_funds{ a.first, a.second });
|
||||
|
||||
for (const auto& a : ammounts_from)
|
||||
proposal_info.from.push_back(view::asset_funds{ a.first, a.second });
|
||||
|
||||
for (const auto&in : tx.vin)
|
||||
//read amounts already provided by third party
|
||||
size_t zc_current_index = 0; //some inputs might be old ones, so it's asset id assumed as native and there is no entry for it in real_zc_ins_asset_ids
|
||||
//THROW_IF_FALSE_WALLET_INT_ERR_EX(ionic_context.gen_context.input_amounts.size() == tx.vin.size(), "Tx gen context has mismatch with tx(amount != amount)");
|
||||
for (i = 0; i != tx.vin.size(); i++)
|
||||
{
|
||||
if (in.type() != typeid(currency::txin_zc_input))
|
||||
size_t mx = 0;
|
||||
uint64_t amount = 0;
|
||||
crypto::public_key in_asset_id = currency::native_coin_asset_id;
|
||||
if (tx.vin[i].type() == typeid(txin_zc_input))
|
||||
{
|
||||
in_asset_id = ionic_context.gen_context.real_zc_ins_asset_ids[zc_current_index].to_public_key();
|
||||
amount = ionic_context.gen_context.input_amounts[zc_current_index];
|
||||
zc_current_index++;
|
||||
mx = boost::get<currency::txin_zc_input>(tx.vin[i]).key_offsets.size() - 1;
|
||||
}
|
||||
else if (tx.vin[i].type() == typeid(txin_to_key))
|
||||
{
|
||||
amount = boost::get<txin_to_key>(tx.vin[i]).amount;
|
||||
mx = boost::get<currency::txin_to_key>(tx.vin[i]).key_offsets.size() - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
WLT_LOG_RED("Unexpected type of input in ionic_swap tx: " << tx.vin[i].type().name(), LOG_LEVEL_0);
|
||||
return false;
|
||||
size_t mx = boost::get<currency::txin_zc_input>(in).key_offsets.size() - 1;
|
||||
}
|
||||
amounts_provided_by_a[in_asset_id] += amount;
|
||||
|
||||
if (proposal_info.mixins == 0 || proposal_info.mixins > mx)
|
||||
{
|
||||
proposal_info.mixins = mx;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
proposal_info.fee = currency::get_tx_fee(tx);
|
||||
//this might be 0, if Alice don't want to pay fee herself
|
||||
proposal_info.fee_paid_by_a = currency::get_tx_fee(tx);
|
||||
if (proposal_info.fee_paid_by_a)
|
||||
{
|
||||
THROW_IF_FALSE_WALLET_INT_ERR_EX(amounts_provided_by_a[currency::native_coin_asset_id] >= proposal_info.fee_paid_by_a, "Fee mentioned as specified but not provided by A");
|
||||
amounts_provided_by_a[currency::native_coin_asset_id] -= proposal_info.fee_paid_by_a;
|
||||
}
|
||||
|
||||
//proposal_info.fee = currency::get_tx_fee(tx);
|
||||
//need to make sure that funds for Bob properly funded
|
||||
for (const auto& a : ammounts_to_b)
|
||||
{
|
||||
uint64_t amount_sent_back_to_alice = ammounts_to_a[a.first];
|
||||
|
||||
if (amounts_provided_by_a[a.first] < (a.second + amount_sent_back_to_alice) )
|
||||
{
|
||||
WLT_LOG_RED("Amount[" << a.first << "] provided by Alice(" << amounts_provided_by_a[a.first] << ") is less then transfered to Bob(" << a.second <<")", LOG_LEVEL_0);
|
||||
return false;
|
||||
}
|
||||
amounts_provided_by_a[a.first] -= (amount_sent_back_to_alice + a.second);
|
||||
proposal_info.to_bob.push_back(view::asset_funds{ a.first, a.second });
|
||||
//clean accounted assets
|
||||
ammounts_to_a.erase(ammounts_to_a.find(a.first));
|
||||
if (amounts_provided_by_a[a.first] > 0)
|
||||
{
|
||||
WLT_LOG_RED("Amount[" << a.first << "] provided by Alice has unused leftovers: " << amounts_provided_by_a[a.first], LOG_LEVEL_0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//need to see what Alice actually expect in return
|
||||
for (const auto& a : ammounts_to_a)
|
||||
{
|
||||
//now amount provided by A should be less or equal to what we have in a.second
|
||||
if (amounts_provided_by_a[a.first] > a.second)
|
||||
{
|
||||
//could be fee
|
||||
WLT_LOG_RED("Amount[" << a.first << "] provided by Alice has unused leftovers: " << amounts_provided_by_a[a.first], LOG_LEVEL_0);
|
||||
return false;
|
||||
}
|
||||
|
||||
proposal_info.to_alice.push_back(view::asset_funds{ a.first, a.second - amounts_provided_by_a[a.first] });
|
||||
}
|
||||
|
||||
etc_tx_details_expiration_time t = AUTO_VAL_INIT(t);
|
||||
if (!get_type_in_variant_container(tx.extra, t))
|
||||
{
|
||||
|
|
@ -5174,7 +5240,7 @@ bool wallet2::accept_ionic_swap_proposal(const wallet_public::ionic_swap_proposa
|
|||
this->balance(balances, mined);
|
||||
//validate balances needed
|
||||
uint64_t native_amount_required = 0;
|
||||
for (const auto& item : msc.proposal_info.to)
|
||||
for (const auto& item : msc.proposal_info.to_alice)
|
||||
{
|
||||
if (balances[item.asset_id].unlocked < item.amount)
|
||||
{
|
||||
|
|
@ -5188,9 +5254,9 @@ bool wallet2::accept_ionic_swap_proposal(const wallet_public::ionic_swap_proposa
|
|||
|
||||
// balances is ok, check if fee is added to tx
|
||||
uint64_t additional_fee = 0;
|
||||
if (msc.proposal_info.fee < m_core_runtime_config.tx_default_fee)
|
||||
if (msc.proposal_info.fee_paid_by_a < m_core_runtime_config.tx_default_fee)
|
||||
{
|
||||
additional_fee = m_core_runtime_config.tx_default_fee - msc.proposal_info.fee;
|
||||
additional_fee = m_core_runtime_config.tx_default_fee - msc.proposal_info.fee_paid_by_a;
|
||||
if (balances[currency::native_coin_asset_id].unlocked < additional_fee + native_amount_required)
|
||||
{
|
||||
return false;
|
||||
|
|
@ -5540,11 +5606,16 @@ assets_selection_context wallet2::get_needed_money(uint64_t fee, const std::vect
|
|||
|
||||
THROW_IF_TRUE_WALLET_EX(0 == dt.amount, error::zero_destination);
|
||||
uint64_t money_to_add = dt.amount;
|
||||
if (dt.amount_to_provide)
|
||||
if (dt.amount_to_provide || dt.flags & tx_destination_entry_flags::tdef_explicit_amount_to_provide)
|
||||
money_to_add = dt.amount_to_provide;
|
||||
|
||||
amounts_map[dt.asset_id].needed_amount += money_to_add;
|
||||
THROW_IF_TRUE_WALLET_EX(amounts_map[dt.asset_id].needed_amount < money_to_add, error::tx_sum_overflow, dsts, fee);
|
||||
//clean up empty entries
|
||||
if (amounts_map[dt.asset_id].needed_amount == 0)
|
||||
{
|
||||
amounts_map.erase(amounts_map.find(dt.asset_id));
|
||||
}
|
||||
}
|
||||
return std::move(amounts_map);
|
||||
}
|
||||
|
|
@ -6253,7 +6324,7 @@ void wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx
|
|||
if (ctp.flags & TX_FLAG_SIGNATURE_MODE_SEPARATE && tx_for_mode_separate.vout.size() )
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(get_tx_flags(tx_for_mode_separate) & TX_FLAG_SIGNATURE_MODE_SEPARATE, "tx_param.flags differs from tx.flags");
|
||||
for (const auto& el : mode_separatemode_separate.proposal_info.to)
|
||||
for (const auto& el : mode_separatemode_separate.proposal_info.to_alice)
|
||||
{
|
||||
needed_money_map[el.asset_id].needed_amount += el.amount;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1195,18 +1195,18 @@ namespace wallet_public
|
|||
|
||||
struct ionic_swap_proposal_info
|
||||
{
|
||||
std::vector<asset_funds> from;
|
||||
std::vector<asset_funds> to;
|
||||
std::vector<asset_funds> to_bob; //assets that funded by side that making proposal(Alice) and addressed to receiver of proposal (Bob)
|
||||
std::vector<asset_funds> to_alice; //assets expected to be funded by the side that receiving proposal (Bob) and addressed to Alice
|
||||
uint64_t mixins;
|
||||
uint64_t fee;
|
||||
uint64_t fee_paid_by_a;
|
||||
uint64_t expiration_time;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
|
||||
KV_SERIALIZE(from)
|
||||
KV_SERIALIZE(to)
|
||||
KV_SERIALIZE(to_bob)
|
||||
KV_SERIALIZE(to_alice)
|
||||
KV_SERIALIZE(mixins)
|
||||
KV_SERIALIZE(fee)
|
||||
KV_SERIALIZE(fee_paid_by_a)
|
||||
KV_SERIALIZE(expiration_time)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,12 @@ ionic_swap_basic_test::ionic_swap_basic_test()
|
|||
|
||||
bool ionic_swap_basic_test::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
uint64_t ts = test_core_time::get_time();
|
||||
// NOTE: This test is made deterministic to be able to correctly set up checkpoint.
|
||||
random_state_test_restorer::reset_random(); // random generator's state was previously stored, will be restore on dtor (see also m_random_state_test_restorer)
|
||||
uint64_t ts = 1450000000;
|
||||
test_core_time::adjust(ts);
|
||||
|
||||
ts = test_core_time::get_time();
|
||||
m_accounts.resize(TOTAL_ACCS_COUNT);
|
||||
currency::account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts);
|
||||
currency::account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts);
|
||||
|
|
@ -126,19 +131,23 @@ bool ionic_swap_basic_test::c1(currency::core& c, size_t ev_index, const std::ve
|
|||
//alice_wlt want to trade with miner_wlt, to exchange 10.0 TCT to 1.0 ZANO
|
||||
view::ionic_swap_proposal_info proposal_details = AUTO_VAL_INIT(proposal_details);
|
||||
proposal_details.expiration_time = alice_wlt->get_core_runtime_config().get_core_time() + 10 * 60;
|
||||
proposal_details.fee = TESTS_DEFAULT_FEE;
|
||||
proposal_details.fee_paid_by_a = TESTS_DEFAULT_FEE;
|
||||
proposal_details.mixins = 10;
|
||||
proposal_details.from.push_back(view::asset_funds{ asset_id , assets_to_exchange });
|
||||
proposal_details.to.push_back(view::asset_funds{ currency::native_coin_asset_id , native_tokens_to_exchange });
|
||||
proposal_details.to_bob.push_back(view::asset_funds{ asset_id , assets_to_exchange });
|
||||
proposal_details.to_alice.push_back(view::asset_funds{ currency::native_coin_asset_id , native_tokens_to_exchange });
|
||||
|
||||
tools::wallet_public::ionic_swap_proposal proposal = AUTO_VAL_INIT(proposal);
|
||||
alice_wlt->create_ionic_swap_proposal(proposal_details, miner_wlt->get_account().get_public_address(), proposal);
|
||||
|
||||
view::ionic_swap_proposal_info proposal_decoded_info;
|
||||
view::ionic_swap_proposal_info proposal_decoded_info = AUTO_VAL_INIT(proposal_decoded_info);
|
||||
miner_wlt->get_ionic_swap_proposal_info(proposal, proposal_decoded_info);
|
||||
|
||||
//Validate proposal
|
||||
if (proposal_decoded_info.from != proposal_details.from || proposal_decoded_info.to != proposal_details.to)
|
||||
if (proposal_decoded_info.to_bob != proposal_details.to_bob
|
||||
|| proposal_decoded_info.to_alice != proposal_details.to_alice
|
||||
|| proposal_decoded_info.fee_paid_by_a != proposal_details.fee_paid_by_a
|
||||
|| proposal_decoded_info.mixins != proposal_details.mixins
|
||||
)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(false, false, "proposal actual and proposals decoded mismatch");
|
||||
}
|
||||
|
|
@ -171,6 +180,12 @@ bool ionic_swap_basic_test::c1(currency::core& c, size_t ev_index, const std::ve
|
|||
CHECK_AND_ASSERT_MES(it_asset != balances.end(), false, "Failed to find needed asset in result balances");
|
||||
CHECK_AND_ASSERT_MES(it_native->second.total == mined_balance - native_tokens_to_exchange, false, "Failed to find needed asset in result balances");
|
||||
CHECK_AND_ASSERT_MES(it_asset->second.total == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC + assets_to_exchange, false, "Failed to find needed asset in result balances");
|
||||
|
||||
|
||||
//TODO:
|
||||
// add fee paid by bob scenario
|
||||
// add transfer of tokens without native coins
|
||||
// different fail combination
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,12 +4,15 @@
|
|||
#pragma once
|
||||
#include "chaingen.h"
|
||||
#include "wallet_tests_basic.h"
|
||||
|
||||
#include "random_helper.h"
|
||||
|
||||
struct ionic_swap_basic_test : public wallet_test
|
||||
{
|
||||
ionic_swap_basic_test();
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
|
||||
private:
|
||||
random_state_test_restorer m_random_state_test_restorer;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue