BlockPo / BlockPo-to-Tradelayer

Incubation Repo for the TradeLayer protocol, 0.2.0
http://www.tradelayer.org
Other
8 stars 8 forks source link

Define Expiration Logic #158

Closed patrickdugan closed 4 years ago

patrickdugan commented 4 years ago

Pulling this out of the Perpetual Swap ticket:

On expiration a few things happen:

1) The expiration flag is set to the contract object with sp id# n to be 1 or "true".
2) Rules about validity of on-chain ContractDex trades, trade channel Contract trades, that invalidate any tx relating to a contract whose expiration flag has triggered.
3) The final array of address<->address * contracts is resolved with netting events as if both sides traded together at the expiration price to settle out. Normally this set is passed through the container vector to be reference in a contract's subsequent settlements but here there are no future settlements.

 4) The insurance fund for the given contract pays into the insurance fund for the next contract in its series (it may merit storing the successor contract id in the object of the expiring contract when it is created).
santos177 commented 4 years ago

working in expiration branch

patrickdugan commented 4 years ago

When a contract is created, whether it is a predefined native futures contract (to be fixed for the upcoming native release, so that would be a logic that enacts on the activation block) or an oracle, and it's expiration>0 then a successor contract is also created, ideally having twin property ids.

When this happens, the first contract gets assigned a field "successor" with the id of the next one. We'll call this successor(2)

(Unfortunately the successor to the successor will not have twin property ids, it'll have a random next-number SP id like any other new property.)

When a contract is <10% of the way to expiry, rounded_down to the nearest block, the successor(3) is created, assigned a property id, and successor(2) gets assigned in its "successor" field the id of that new contract, where that value was previous null. And so on for successor(N) until an oracle future is retired, or indefinitely for the native ones.

Then therefore, we reference when a contract expires, its successor id, and simply debit its entire insurance fund and credit the fund of the successor.

patrickdugan commented 4 years ago

std::vector<std::map<std::string, std::string>> lives_longs_vg;

and

std::vector<std::map<std::string, std::string>> lives_shorts_vg;

Show up in globals.cpp and tradelayer.cpp at line 2457, right after the main tx handler function starts.

patrickdugan commented 4 years ago

Ok the plot thickens, these functions prepare the operation around the set of surviving positions in a perpetual swap. The truth is though, we need this for all contracts, not just perpetuals, as futures go through a series of settlements prior to their final expiration. So we have to generalize these lives Vectors in LevelDB as we do with path_elef.

void lookingin_globalvector_pastlivesperpetuals(std::vector<std::map<std::string, std::string>> &lives_g, MatrixTLS M_file, std::vector addrs_vg, std::vector<std::map<std::string, std::string>> &lives_h) { for (std::vector::iterator it = addrs_vg.begin(); it != addrs_vg.end(); ++it) lookingaddrs_inside_M_file(*it, M_file, lives_g, lives_h); }

void lookingaddrs_inside_M_file(std::string addrs, MatrixTLS M_file, std::vector<std::map<std::string, std::string>> &lives_g, std::vector<std::map<std::string, std::string>> &lives_h) { for (int i = 0; i < size(M_file, 0); ++i) { VectorTLS jrow_database(size(M_file, 1)); sub_row(jrow_database, M_file, i); struct status_amounts *pt_status_amounts_byaddrs = get_status_amounts_byaddrs(jrow_database, addrs);

  /***********************************************************************************/
  /** Checking if the address is inside the new settlement database **/
  if (addrs == pt_status_amounts_byaddrs->addrs_src || addrs == pt_status_amounts_byaddrs->addrs_trk)
{
  for (std::vector<std::map<std::string, std::string>>::iterator it = lives_g.begin(); it != lives_g.end(); ++it)
    {
      struct status_lives_edge *pt_status_bylivesedge = get_status_bylivesedge(*it);
      if (addrs == pt_status_bylivesedge->addrs)
    lives_h.push_back(*it);
    }
  break;
}

Then there's another vector just called "lives" which is used here:

int finding_idxforaddress(std::string addrs, std::vector<std::map<std::string, std::string>> lives) { int idx_q = 0; for (std::vector<std::map<std::string, std::string>>::iterator it = lives.begin(); it != lives.end(); ++it) { idx_q += 1; struct status_lives_edge pt_status_bylivesedge = get_status_bylivesedge(it); if (addrs == pt_status_bylivesedge->addrs) break; } return idx_q-1; }

Looks like an interator function on that vector. However it is only called in commented-out code, so it seems the lives_g and lives_h system is the recent upgrade Lihki did sometime in June.

patrickdugan commented 4 years ago

After some deeper audit and consulting with Lihki, everything is working off the extern vectors in the settlement_fifo function and we're about to log those in the testnet version. The refactors Ale did in a separate branch are going to get merged in later after we've audited the Lihki version on testnet and at the data structure level, we'll do the clean-up after.

Therefore, closing this ticket.