Skip to content

Commit 49fafcf

Browse files
committed
Implement simple collateralized P2P funding
1 parent 7d441c1 commit 49fafcf

37 files changed

+1649
-63
lines changed

libraries/chain/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ add_library( graphene_chain
3939
evaluator.cpp
4040
liquidity_pool_evaluator.cpp
4141
samet_fund_evaluator.cpp
42+
credit_offer_evaluator.cpp
4243
balance_evaluator.cpp
4344
account_evaluator.cpp
4445
assert_evaluator.cpp

libraries/chain/credit_offer_evaluator.cpp

Lines changed: 454 additions & 0 deletions
Large diffs are not rendered by default.

libraries/chain/db_block.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,7 @@ void database::_apply_block( const signed_block& next_block )
648648
update_expired_feeds(); // this will update expired feeds and some core exchange rates
649649
update_core_exchange_rates(); // this will update remaining core exchange rates
650650
update_withdraw_permissions();
651+
update_credit_offers_and_deals();
651652

652653
// n.b., update_maintenance_flag() happens this late
653654
// because get_slot_time() / get_slot_at_time() is needed above

libraries/chain/db_init.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <graphene/chain/chain_property_object.hpp>
3434
#include <graphene/chain/committee_member_object.hpp>
3535
#include <graphene/chain/confidential_object.hpp>
36+
#include <graphene/chain/credit_offer_object.hpp>
3637
#include <graphene/chain/fba_object.hpp>
3738
#include <graphene/chain/global_property_object.hpp>
3839
#include <graphene/chain/liquidity_pool_object.hpp>
@@ -57,6 +58,7 @@
5758
#include <graphene/chain/balance_evaluator.hpp>
5859
#include <graphene/chain/committee_member_evaluator.hpp>
5960
#include <graphene/chain/confidential_evaluator.hpp>
61+
#include <graphene/chain/credit_offer_evaluator.hpp>
6062
#include <graphene/chain/custom_evaluator.hpp>
6163
#include <graphene/chain/liquidity_pool_evaluator.hpp>
6264
#include <graphene/chain/market_evaluator.hpp>
@@ -138,6 +140,11 @@ void database::initialize_evaluators()
138140
register_evaluator<samet_fund_update_evaluator>();
139141
register_evaluator<samet_fund_borrow_evaluator>();
140142
register_evaluator<samet_fund_repay_evaluator>();
143+
register_evaluator<credit_offer_create_evaluator>();
144+
register_evaluator<credit_offer_delete_evaluator>();
145+
register_evaluator<credit_offer_update_evaluator>();
146+
register_evaluator<credit_offer_accept_evaluator>();
147+
register_evaluator<credit_deal_repay_evaluator>();
141148
}
142149

143150
void database::initialize_indexes()
@@ -165,6 +172,8 @@ void database::initialize_indexes()
165172
add_index< primary_index<ticket_index> >();
166173
add_index< primary_index<liquidity_pool_index> >();
167174
add_index< primary_index<samet_fund_index> >();
175+
add_index< primary_index<credit_offer_index> >();
176+
add_index< primary_index<credit_deal_index> >();
168177

169178
//Implementation object indexes
170179
add_index< primary_index<transaction_index > >();
@@ -185,6 +194,7 @@ void database::initialize_indexes()
185194
add_index< primary_index< buyback_index > >();
186195
add_index< primary_index<collateral_bid_index > >();
187196
add_index< primary_index< simple_index< fba_accumulator_object > > >();
197+
add_index< primary_index<credit_deal_summary_index > >();
188198
}
189199

190200
} }

libraries/chain/db_notify.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <graphene/chain/ticket_object.hpp>
2121
#include <graphene/chain/liquidity_pool_object.hpp>
2222
#include <graphene/chain/samet_fund_object.hpp>
23+
#include <graphene/chain/credit_offer_object.hpp>
2324
#include <graphene/chain/impacted.hpp>
2425
#include <graphene/chain/hardfork.hpp>
2526

@@ -356,6 +357,31 @@ struct get_impacted_account_visitor
356357
{
357358
_impacted.insert( op.fee_payer() ); // account
358359
}
360+
void operator()( const credit_offer_create_operation& op )
361+
{
362+
_impacted.insert( op.fee_payer() ); // owner_account
363+
}
364+
void operator()( const credit_offer_delete_operation& op )
365+
{
366+
_impacted.insert( op.fee_payer() ); // owner_account
367+
}
368+
void operator()( const credit_offer_update_operation& op )
369+
{
370+
_impacted.insert( op.fee_payer() ); // owner_account
371+
}
372+
void operator()( const credit_offer_accept_operation& op )
373+
{
374+
_impacted.insert( op.fee_payer() ); // borrower
375+
}
376+
void operator()( const credit_deal_repay_operation& op )
377+
{
378+
_impacted.insert( op.fee_payer() ); // account
379+
}
380+
void operator()( const credit_deal_expired_operation& op )
381+
{
382+
_impacted.insert( op.offer_owner );
383+
_impacted.insert( op.borrower );
384+
}
359385
};
360386

361387
} // namespace detail
@@ -474,6 +500,17 @@ void get_relevant_accounts( const object* obj, flat_set<account_id_type>& accoun
474500
FC_ASSERT( aobj != nullptr );
475501
accounts.insert( aobj->owner_account );
476502
break;
503+
} case credit_offer_object_type:{
504+
const auto* aobj = dynamic_cast<const credit_offer_object*>( obj );
505+
FC_ASSERT( aobj != nullptr );
506+
accounts.insert( aobj->owner_account );
507+
break;
508+
} case credit_deal_object_type:{
509+
const auto* aobj = dynamic_cast<const credit_deal_object*>( obj );
510+
FC_ASSERT( aobj != nullptr );
511+
accounts.insert( aobj->offer_owner );
512+
accounts.insert( aobj->borrower );
513+
break;
477514
}
478515
}
479516
}
@@ -537,6 +574,12 @@ void get_relevant_accounts( const object* obj, flat_set<account_id_type>& accoun
537574
FC_ASSERT( aobj != nullptr );
538575
accounts.insert( aobj->bidder );
539576
break;
577+
} case impl_credit_deal_summary_object_type:{
578+
const auto& aobj = dynamic_cast<const credit_deal_summary_object*>(obj);
579+
FC_ASSERT( aobj != nullptr );
580+
accounts.insert( aobj->offer_owner );
581+
accounts.insert( aobj->borrower );
582+
break;
540583
}
541584
}
542585
}

libraries/chain/db_update.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <graphene/chain/db_with.hpp>
2727

2828
#include <graphene/chain/asset_object.hpp>
29+
#include <graphene/chain/credit_offer_object.hpp>
2930
#include <graphene/chain/global_property_object.hpp>
3031
#include <graphene/chain/hardfork.hpp>
3132
#include <graphene/chain/htlc_object.hpp>
@@ -697,4 +698,74 @@ generic_operation_result database::process_tickets()
697698
return result;
698699
}
699700

701+
void database::update_credit_offers_and_deals()
702+
{
703+
const auto head_time = head_block_time();
704+
705+
// Auto-disable offers
706+
const auto& offer_idx = get_index_type<credit_offer_index>().indices().get<by_auto_disable_time>();
707+
auto offer_itr = offer_idx.lower_bound( true );
708+
auto offer_itr_end = offer_idx.upper_bound( boost::make_tuple( true, head_time ) );
709+
while( offer_itr != offer_itr_end )
710+
{
711+
const credit_offer_object& offer = *offer_itr;
712+
++offer_itr;
713+
modify( offer, []( credit_offer_object& obj ) {
714+
obj.enabled = false;
715+
});
716+
}
717+
718+
// Auto-process deals
719+
const auto& deal_idx = get_index_type<credit_deal_index>().indices().get<by_latest_repay_time>();
720+
const auto& deal_summary_idx = get_index_type<credit_deal_summary_index>().indices().get<by_offer_borrower>();
721+
auto deal_itr_end = deal_idx.upper_bound( head_time );
722+
for( auto deal_itr = deal_idx.begin(); deal_itr != deal_itr_end; deal_itr = deal_idx.begin() )
723+
{
724+
const credit_deal_object& deal = *deal_itr;
725+
726+
// Update offer
727+
// Note: offer balance can be zero after updated. TODO remove zero-balance offers after a period
728+
const credit_offer_object& offer = deal.offer_id(*this);
729+
modify( offer, [&deal]( credit_offer_object& obj ){
730+
obj.total_balance -= deal.debt_amount;
731+
});
732+
733+
// Process deal summary
734+
auto summ_itr = deal_summary_idx.find( boost::make_tuple( deal.offer_id, deal.borrower ) );
735+
if( summ_itr == deal_summary_idx.end() ) // This should not happen, just be defensive here
736+
{
737+
// We do not do FC_ASSERT or FC_THROW here to avoid halting the chain
738+
elog( "Error: unable to find the credit deal summary object for credit deal ${d}",
739+
("d", deal) );
740+
}
741+
else
742+
{
743+
const credit_deal_summary_object& summ_obj = *summ_itr;
744+
if( summ_obj.total_debt_amount == deal.debt_amount )
745+
{
746+
remove( summ_obj );
747+
}
748+
else
749+
{
750+
modify( summ_obj, [&deal]( credit_deal_summary_object& obj ){
751+
obj.total_debt_amount -= deal.debt_amount;
752+
});
753+
}
754+
}
755+
756+
// Adjust balance
757+
adjust_balance( deal.offer_owner, asset( deal.collateral_amount, deal.collateral_asset ) );
758+
759+
// Notify related parties
760+
push_applied_operation( credit_deal_expired_operation (
761+
deal.id, deal.offer_id, deal.offer_owner, deal.borrower,
762+
asset( deal.debt_amount, deal.debt_asset ),
763+
asset( deal.collateral_amount, deal.collateral_asset ),
764+
deal.fee_rate ) );
765+
766+
// Remove the deal
767+
remove( deal );
768+
}
769+
}
770+
700771
} }
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// bitshares-core issue #2362 Simple collateralized P2P funding
2+
#ifndef HARDFORK_CORE_2362_TIME
3+
// Jan 1 2030, midnight; this is a dummy date until a hardfork date is scheduled
4+
#define HARDFORK_CORE_2362_TIME (fc::time_point_sec( 1893456000 ))
5+
#define HARDFORK_CORE_2362_PASSED(now) (now >= HARDFORK_CORE_2362_TIME)
6+
#endif
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright (c) 2021 Abit More, and contributors.
3+
*
4+
* The MIT License
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
#pragma once
25+
#include <graphene/chain/evaluator.hpp>
26+
27+
#include <graphene/protocol/credit_offer.hpp>
28+
29+
namespace graphene { namespace chain {
30+
31+
class credit_offer_object;
32+
33+
class credit_offer_create_evaluator : public evaluator<credit_offer_create_evaluator>
34+
{
35+
public:
36+
using operation_type = credit_offer_create_operation;
37+
38+
void_result do_evaluate( const credit_offer_create_operation& op ) const;
39+
object_id_type do_apply( const credit_offer_create_operation& op ) const;
40+
};
41+
42+
class credit_offer_delete_evaluator : public evaluator<credit_offer_delete_evaluator>
43+
{
44+
public:
45+
using operation_type = credit_offer_delete_operation;
46+
47+
void_result do_evaluate( const credit_offer_delete_operation& op );
48+
asset do_apply( const credit_offer_delete_operation& op ) const;
49+
50+
const credit_offer_object* _offer = nullptr;
51+
};
52+
53+
class credit_offer_update_evaluator : public evaluator<credit_offer_update_evaluator>
54+
{
55+
public:
56+
using operation_type = credit_offer_update_operation;
57+
58+
void_result do_evaluate( const credit_offer_update_operation& op );
59+
void_result do_apply( const credit_offer_update_operation& op ) const;
60+
61+
const credit_offer_object* _offer = nullptr;
62+
};
63+
64+
class credit_offer_accept_evaluator : public evaluator<credit_offer_accept_evaluator>
65+
{
66+
public:
67+
using operation_type = credit_offer_accept_operation;
68+
69+
void_result do_evaluate( const credit_offer_accept_operation& op );
70+
extendable_operation_result do_apply( const credit_offer_accept_operation& op ) const;
71+
72+
const credit_offer_object* _offer = nullptr;
73+
const credit_deal_summary_object* _deal_summary = nullptr;
74+
};
75+
76+
class credit_deal_repay_evaluator : public evaluator<credit_deal_repay_evaluator>
77+
{
78+
public:
79+
using operation_type = credit_deal_repay_operation;
80+
81+
void_result do_evaluate( const credit_deal_repay_operation& op );
82+
extendable_operation_result do_apply( const credit_deal_repay_operation& op ) const;
83+
84+
const credit_deal_object* _deal = nullptr;
85+
};
86+
87+
} } // graphene::chain

0 commit comments

Comments
 (0)