BlockPo / BlockPo-to-Tradelayer

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

Perpetual Swap = null expiration #134

Closed patrickdugan closed 4 years ago

patrickdugan commented 4 years ago

Add if statement in tradelayer.cpp settlement that will engage the interest code if expiration = 0 or null.

To hardcore the oracle contract for testing, grab the vector of the oracle data for the settlement period, take a TWAP of that vector for the number of blocks in the settlement period, and plug into the interest formula, the VWAP of the contracts, minus that TWAP.

Passing a null or 0 parameter to CreateContract for expiration creates the contract as a perpetual swap.

patrickdugan commented 4 years ago

The tx parse for create contract doesn't have logic regarding a 0 or null expiration parameter triggering a different class loading process to make the contract a perpetual one. This would go around line 1000 in tx.cpp and then

prop_type = ALL_PROPERTY_TYPE_CONTRACT;

This maybe could be subdivided into two property types, futures vs. swap contracts. Or parameterize this. This would require making modifications in the sp.cpp file. The logic exists in TradeLayer.cpp to trade Perpetual contracts differently, but the intermediate bridge must be written.

patrickdugan commented 4 years ago

sp.h

line 293

/* New things for Contracts / bool isPropertyContract(uint32_t propertyId);

We may need a new bool function like this for whether or not a property is a swap.

santos177 commented 4 years ago

working in branch swap

patrickdugan commented 4 years ago

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).

patrickdugan commented 4 years ago

Made a visual for tracking all the big globals and vars and structs

DataStructure Map

patrickdugan commented 4 years ago

Summary from today:

Deep in the end of the Settlement bracket part of the tx_handler function, around line 2700 or so, is a call of the Settlement_Fifo algorithm that passes a settlement price. Above here is hardcoded ALL and DUSD values which were rigged for a demo a year ago, now we're going to loop through and generalize.

However there is a problem, Lihki has yet to optimize the DB shuffling of the path_elef vector (which is an index of trades) and it is currently somehow drawing out a matrix from M_file using the FillingMatrix function which slots up the vector components of the path_elef relevant to the particular contract. What is somewhat unclear still is how contracts are sorted within the path_elef global.

For this week's purposes, we want to demo a general oracle contract for BTC/USD margined in an issued token e.g. a bankUSD coin or a wrapped-BTC receipt. We don't need to hack a new global var for this, instead figure out how to load that up. Additionally, replace the 3 instances of hardcoding ALL/USD data around lines 300, 600 in Clearing.cpp as well as the instanced mentioned above. With this, we may be able to get the functionality we were hoping for.

Additional notes:

Before we get a lot of contracts going on testnet we will let Lihki complete his DB sorting/optimization of the handling of all the index data about the various contracts to-be-settled.

Path_eleg is vestigial to an attempted work-around to the above problem. Path_ele is an index of matches, it is only invoked in one function in clearing.cpp Lives long/short vectors are equivalent to the concept of a container. The issue of DB optimization for N contracts is related to the congruency of these datastructures. Think about looping through two arrays where the algo will fail if the arrays do not have some pre-existing symmetry.

We can knock out the refactoring of those three parts, dig in some more on Path_elef mechanics, and getting a BTC/USD live this week is probably still achievable. Otherwise we can get some calvary help next week when Lihki is back, and further generalize the issue in any case.

patrickdugan commented 4 years ago

Also, there is a default settlement and a perpetual settlement. The original concept was that perpetuals were like a special case of futures, and periodic settlement of those was not a fore-thought in the dev pipeline until sometime in 2019 or late '18. So now we ideally would treat everything as a contract that settles periodically, and only call the expiration-like settlement algo when it is an expiration block, but otherwise call the perpetual settlement algo every 4 hours.

I've decided it makes sense to bottleneck settlements to once every 4 hours in the entire protocol irrespective of when the contract is created. This way a client can be optimized to only check on those occasional block, what is the settlement price of its own live wallet positions, and save time, while backlogging the work of crunching through all of them. So it's possible to have RPC responsivity on low enough latencies that are usable for a trader algo handling expiring contracts and caring a lot about those last 50 TWAP prints. It's important to node reward to be able to crunch the consensus hash in a reasonable amount of time, and having to crunch things every block or chaotically based on a random distribution of settlement times, is worse. Unless of course the backlog were so extreme that it created a lag on most PCs that exceeded the avg. expected block time.

It seems like the time in which a settlement occurs is also a singular value rather than affixed by contract (though this is not the case for expiration).

I'd prefer to see what kind of peformance benchmarks we hit after Lihki implements this DB optimization for N contract settlements, doing them all on one block. Do we expect there to be a lot of active Oracle contracts in this protocol? The # of native contracts is constrained. Competition and power laws tells you sure you might see hundreds of contracts that do volume (the completion time of the settlement algo is going to grow geometrically by the size of the path_elef's they look through and also by the number of vertices in that graph, so # addresses growing linearly can compound time lag in crunching a graph), so the constraints are more likely to be total throughput of settlement transactions and block-size limits than hyper-abundant #s of Oracles adding to the computation workload.

patrickdugan commented 4 years ago

For clarity:

1) VWAP of Oracle Contract - TWAP of Oracle Feed is the interest rate difference we use to compute perpetual swap interest.

2) VWAP of Native Contact - VWAP of Native Pair is the way to get interest for those native perp. swaps.

3) TWAP of Oracle Feed is used to Mark Price Liquidate Oracle Contracts

4) VWAP of Token pair and Contract in some combination are used to Mark Price Liquidate Native Contracts

5) TWAP of Oracle Feed on longer timeframe used to settle Oracle Contract

6) VWAP of token pair on longer timeframe used to settle Native.

patrickdugan commented 4 years ago

Since we've got a generalization ticket open we can close this ticket once we've tested that our hardcoded contracts generated with expiration blocks = 0 and expiration blocks = e.g. 17280 (monthly future) and check that the hardcodes flow properly.

santos177 commented 4 years ago

code written. we need QA.