mit-dci / opencx

An open-source cryptocurrency exchange toolkit for implementing experimental exchange features
MIT License
206 stars 66 forks source link

"Pinky swear" settlement #28

Closed Rjected closed 5 years ago

Rjected commented 5 years ago

Is your feature request related to a problem? Please describe. Traditional securities exchanges (like NASDAQ) have what I call "pinky swear" settlement, where the broker placing the order promises they can provide the funds for the trade that is being placed. This allows exchanges not to take custody of assets, and instead just make sure that they maintain some sort of reputation per user. Allowing users that regularly cause settlement failures means honest traders won't want to use the exchange. Settlement failures are recorded by the SEC here. We should build out this type of settlement to compare the architectures of traditional securities exchanges and cryptocurrency exchanges, just as we compare custodial and non-custodial settlement architectures (database / internal accounting vs channels, atomic swaps).

Describe the solution you'd like "Pinky swear" settlement is, at most, just making sure users placing orders are on a whitelist. The SettlementEngine's CheckValid method will extremely easy, just verifying that the *match.SettlementExecution Pubkey is on a whitelist. A proper API for the engine (for use by the server / exchange only) will have to be made if you want to implement changes to the whitelist. A minimal pinky swear settlement engine written in literally five minutes:

import (
    "sync"
)
type PinkySwearEngine struct {
    whitelist     map[[33]byte]bool
    whitelistMtx *sync.Mutex
    coin         *coinparam.Params
}
// CreateSettlementEngine creates a settlement engine for a specific coin
func CreateSettlementEngine(coin *coinparam.Params, whitelist [][33]byte) (engine match.SettlementEngine, err error) {
    pe := &PinkySwearEngine{
        coin: coin,
        whitelist: make(map[[33]byte]bool),
        whitelistMtx: new(sync.Mutex),
    }
    pe.whitelistMtx.Lock()
    for _, pubkey := range whitelist {
        pe.whitelist[pubkey] = true
    }
    pe.whitelistMtx.Unlock()
    return
}
// ApplySettlementExecution applies the settlementExecution, this assumes that the settlement execution is
// valid
func (pe *PinkySwearEngine) ApplySettlementExecution(setExec *match.SettlementExecution) (setRes *match.SettlementResult, err error) {
    // this highlights potentially how not generic the SettlementResult struct is, what to put in the NewBal field???
    setRes = &match.SettlementResult{
        // this is where we have sort of undefined on what we do
        NewBal: uint64(0),
        SuccessfulExec: setExec,
    }
    return
}
// CheckValid returns true if the settlement execution would be valid
func (pe *PinkySwearEngine) CheckValid(setExec *match.SettlementExecution) (valid bool, err error) {
    pe.whitelistMtx.Lock()
    if valid, ok = pe.whitelist[setExec.Pubkey]; !ok {
        // just being really explicit here, all this does is check if you're in the whitelist and your value
        // is true. There's no reason for it to be false.
        valid = false
        pe.whitelistMtx.Unlock()
        return
    }
    pe.whitelistMtx.Unlock()
    return
}

Describe alternatives you've considered N/A

Additional context N/A