github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/dlc/contract.go (about)

     1  package dlc
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/mit-dci/lit/lnutil"
     7  )
     8  
     9  const COINTYPE_NOT_SET = ^uint32(0) // Max Uint
    10  
    11  // AddContract starts a new draft contract
    12  func (mgr *DlcManager) AddContract() (*lnutil.DlcContract, error) {
    13  	var err error
    14  
    15  	c := new(lnutil.DlcContract)
    16  	c.Status = lnutil.ContractStatusDraft
    17  	c.CoinType = COINTYPE_NOT_SET
    18  	err = mgr.SaveContract(c)
    19  	if err != nil {
    20  		return nil, err
    21  	}
    22  
    23  	return c, nil
    24  }
    25  
    26  // SetContractOracle assigns a particular oracle to a contract - used for
    27  // determining which pubkey A to use and can also allow for fetching R-points
    28  // automatically when the oracle was imported from a REST api
    29  func (mgr *DlcManager) SetContractOracle(cIdx, oIdx uint64) error {
    30  
    31  	c, err := mgr.LoadContract(cIdx)
    32  	if err != nil {
    33  		return err
    34  	}
    35  
    36  	if c.Status != lnutil.ContractStatusDraft {
    37  		return fmt.Errorf("You cannot change or set the oracle unless the" +
    38  			" contract is in Draft state")
    39  	}
    40  
    41  	o, err := mgr.LoadOracle(oIdx)
    42  	if err != nil {
    43  		return err
    44  	}
    45  
    46  	c.OracleA = o.A
    47  
    48  	// Reset the R point when changing the oracle
    49  	c.OracleR = [33]byte{}
    50  
    51  	mgr.SaveContract(c)
    52  
    53  	return nil
    54  }
    55  
    56  // SetContractSettlementTime sets the unix epoch at which the oracle will sign a
    57  // message containing the value the contract pays out on.
    58  func (mgr *DlcManager) SetContractSettlementTime(cIdx, time uint64) error {
    59  	c, err := mgr.LoadContract(cIdx)
    60  	if err != nil {
    61  		return err
    62  	}
    63  
    64  	if c.Status != lnutil.ContractStatusDraft {
    65  		return fmt.Errorf("You cannot change or set the settlement time" +
    66  			" unless the contract is in Draft state")
    67  	}
    68  
    69  	c.OracleTimestamp = time
    70  
    71  	// Reset the R point
    72  	c.OracleR = [33]byte{}
    73  
    74  	mgr.SaveContract(c)
    75  
    76  	return nil
    77  }
    78  
    79  // SetContractDatafeed will automatically fetch the R-point from the REST API,
    80  // if an oracle is imported from a REST API. You need to set the settlement time
    81  // first, because the R point is a key unique for the time and feed
    82  func (mgr *DlcManager) SetContractDatafeed(cIdx, feed uint64) error {
    83  	c, err := mgr.LoadContract(cIdx)
    84  	if err != nil {
    85  		return err
    86  	}
    87  
    88  	if c.Status != lnutil.ContractStatusDraft {
    89  		return fmt.Errorf("You cannot change or set the Datafeed unless the" +
    90  			" contract is in Draft state")
    91  	}
    92  
    93  	if c.OracleTimestamp == 0 {
    94  		return fmt.Errorf("You need to set the settlement timestamp first," +
    95  			" otherwise no R point can be retrieved for the feed")
    96  	}
    97  
    98  	o, err := mgr.FindOracleByKey(c.OracleA)
    99  	if err != nil {
   100  		return err
   101  	}
   102  
   103  	c.OracleR, err = o.FetchRPoint(feed, c.OracleTimestamp)
   104  	if err != nil {
   105  		return err
   106  	}
   107  
   108  	err = mgr.SaveContract(c)
   109  	if err != nil {
   110  		return err
   111  	}
   112  	return nil
   113  }
   114  
   115  // SetContractRPoint allows you to manually set the R-point key if an oracle is
   116  // not imported from a REST API
   117  func (mgr *DlcManager) SetContractRPoint(cIdx uint64, rPoint [33]byte) error {
   118  	c, err := mgr.LoadContract(cIdx)
   119  	if err != nil {
   120  		return err
   121  	}
   122  
   123  	if c.Status != lnutil.ContractStatusDraft {
   124  		return fmt.Errorf("You cannot change or set the R-point unless the" +
   125  			" contract is in Draft state")
   126  	}
   127  
   128  	c.OracleR = rPoint
   129  
   130  	err = mgr.SaveContract(c)
   131  	if err != nil {
   132  		return err
   133  	}
   134  
   135  	return nil
   136  }
   137  
   138  // SetContractFunding sets the funding to the contract. It will specify how much
   139  // we (the offering party) are funding, as well as
   140  func (mgr *DlcManager) SetContractFunding(cIdx uint64, our, their int64) error {
   141  	c, err := mgr.LoadContract(cIdx)
   142  	if err != nil {
   143  		return err
   144  	}
   145  
   146  	if c.Status != lnutil.ContractStatusDraft {
   147  		return fmt.Errorf("You cannot change or set the funding unless the" +
   148  			" contract is in Draft state")
   149  	}
   150  
   151  	c.OurFundingAmount = our
   152  	c.TheirFundingAmount = their
   153  
   154  	// If the funding changes, the division needs to be re-set.
   155  	c.Division = nil
   156  
   157  	mgr.SaveContract(c)
   158  
   159  	return nil
   160  }
   161  
   162  // SetContractDivision sets the division of the contract settlement. If the
   163  // oraclized value is valueAllOurs, then the entire value of the contract is
   164  // payable to us. If the oraclized value is valueAllTheirs, then the entire
   165  // value is paid to our peer. Between those, the value is divided linearly.
   166  func (mgr *DlcManager) SetContractDivision(cIdx uint64,
   167  	valueAllOurs, valueAllTheirs int64) error {
   168  	c, err := mgr.LoadContract(cIdx)
   169  	if err != nil {
   170  		return err
   171  	}
   172  
   173  	if c.Status != lnutil.ContractStatusDraft {
   174  		return fmt.Errorf("You cannot change or set the division unless" +
   175  			" the contract is in Draft state")
   176  	}
   177  
   178  	rangeMin := valueAllTheirs - (valueAllOurs - valueAllTheirs)
   179  	rangeMax := valueAllOurs + (valueAllOurs - valueAllTheirs)
   180  	oursHighest := true
   181  	if valueAllTheirs > valueAllOurs {
   182  		oursHighest = false
   183  		rangeMin = valueAllOurs - (valueAllTheirs - valueAllOurs)
   184  		rangeMax = valueAllTheirs + (valueAllTheirs - valueAllOurs)
   185  	}
   186  	if rangeMin < 0 {
   187  		rangeMin = 0
   188  	}
   189  
   190  	totalContractValue := c.OurFundingAmount + c.TheirFundingAmount
   191  	fTotal := float64(totalContractValue)
   192  	fRange := float64(valueAllOurs - valueAllTheirs)
   193  	if !oursHighest {
   194  		fRange = float64(valueAllTheirs - valueAllOurs)
   195  	}
   196  	c.Division = make([]lnutil.DlcContractDivision, rangeMax-rangeMin+1)
   197  	for i := rangeMin; i <= rangeMax; i++ {
   198  		c.Division[i-rangeMin].OracleValue = i
   199  
   200  		if (oursHighest && i >= valueAllOurs) ||
   201  			(!oursHighest && i <= valueAllOurs) {
   202  			c.Division[i-rangeMin].ValueOurs = totalContractValue
   203  			continue
   204  		}
   205  
   206  		if (oursHighest && i <= valueAllTheirs) ||
   207  			(!oursHighest && i >= valueAllTheirs) {
   208  			c.Division[i-rangeMin].ValueOurs = 0
   209  			continue
   210  		}
   211  
   212  		idx := i - rangeMin
   213  		if oursHighest {
   214  			fCurInRange := float64(i - valueAllTheirs)
   215  			c.Division[idx].ValueOurs = int64(fTotal / fRange * fCurInRange)
   216  		} else {
   217  			fCurInRange := float64(i - valueAllOurs)
   218  			c.Division[idx].ValueOurs = int64(totalContractValue)
   219  			c.Division[idx].ValueOurs -= int64(fTotal / fRange * fCurInRange)
   220  
   221  		}
   222  
   223  	}
   224  	mgr.SaveContract(c)
   225  
   226  	return nil
   227  }
   228  
   229  // SetContractCoinType sets the cointype for a particular contract
   230  func (mgr *DlcManager) SetContractCoinType(cIdx uint64, cointype uint32) error {
   231  	c, err := mgr.LoadContract(cIdx)
   232  	if err != nil {
   233  		return err
   234  	}
   235  
   236  	if c.Status != lnutil.ContractStatusDraft {
   237  		return fmt.Errorf("You cannot change or set the coin type unless" +
   238  			" the contract is in Draft state")
   239  	}
   240  
   241  	c.CoinType = cointype
   242  
   243  	mgr.SaveContract(c)
   244  
   245  	return nil
   246  }