/// <summary> /// Fix case mistakes /// </summary> private static void FixCasing(Event evt, DiscretePayoffs payoffs) { HashSet <DiscreteOutcome> outcomes = new HashSet <DiscreteOutcome>(); for (int i = 0; i < payoffs.Count; i++) { var outcomeString = payoffs[i].Outcome.OutcomeString?.Trim(); if (outcomeString is null) { throw new CommandException("payoff", "The payoff can't be parsed"); } var knownOutcome = evt.Outcomes.Select(o => new DiscreteOutcome(o)) .FirstOrDefault(o => o.OutcomeString !.Equals(outcomeString, StringComparison.OrdinalIgnoreCase)); if (knownOutcome is null) { throw new CommandException("payoff", $"This outcome {outcomeString} is not part of the event"); } outcomes.Add(knownOutcome); payoffs[i] = new DiscretePayoff(knownOutcome, payoffs[i].Reward); } if (outcomes.Count != evt.Outcomes.Length) { throw new CommandException("payoff", $"You did not specified the reward of all outcomes of the event"); } }
public Money Offer( ECXOnlyPubKey oraclePubKey, SchnorrNonce eventNonce, DiscretePayoffs offererPayoffs, Timeouts timeouts, Money?collateral = null) { using var tx = StartTransaction(); if (!s.IsInitiator) { throw new InvalidOperationException("The acceptor can't initiate an offer"); } s.OracleInfo = new OracleInfo(oraclePubKey, eventNonce); s.Timeouts = timeouts; s.OffererPayoffs = offererPayoffs; s.Offerer = new Party(); var minimumCollateral = offererPayoffs.CalculateMinimumCollateral(); if (collateral is Money m && m < minimumCollateral) { throw new ArgumentException($"The collateral is too small, it should be at least {minimumCollateral.ToString(false, false)}"); } s.Offerer.Collateral = collateral ?? minimumCollateral; tx.Commit(); return(s.Offerer.Collateral); }
private DiscretePayoffs GetOutcomes(string[]?outcomes) { string optionName = "outcome"; if (outcomes is null || outcomes.Length is 0) { throw new CommandOptionRequiredException(optionName); } DiscretePayoffs pnl = new DiscretePayoffs(); for (int i = 0; i < outcomes.Length; i++) { var separator = outcomes[i].LastIndexOf(':'); if (separator == -1) { throw new CommandException(optionName, "Invalid outcome, the format should be \'outcome:reward\' where \'reward\' is in sats (\'1000 sats\') or in BTC (\'0.2\')"); } var outcome = outcomes[i].Substring(0, separator); var reward = outcomes[i].Substring(separator + 1); reward = reward.ToLowerInvariant().Trim(); var satsSeparator = reward.IndexOf("sats"); Money rewardMoney = Money.Zero; if (satsSeparator == -1) { rewardMoney = Money.Parse(reward); } else { rewardMoney = Money.Satoshis(long.Parse(reward.Substring(0, satsSeparator))); } pnl.Add(new DiscretePayoff(outcome, rewardMoney)); } return(pnl); }
public void FillStateFrom(Offer?offer) { if (offer is null) { return; } s.OffererInputs = offer.FundingInputs; s.OffererChange = offer.ChangeAddress?.ScriptPubKey; s.OracleInfo = offer.OracleInfo; s.Timeouts = offer.Timeouts; s.ContractId = offer.GetTemporaryContractId(); s.Offerer ??= new Party(); if (offer.ContractInfo is ContractInfo[] c && c.Length > 0 && offer.TotalCollateral is Money) { s.OffererPayoffs = DiscretePayoffs.CreateFromContractInfo(offer.ContractInfo, offer.TotalCollateral); } s.Offerer.VSizes = new VSizeCalculator(offer).Calculate(); s.Offerer.Collateral = offer.TotalCollateral ?? s.OffererPayoffs?.CalculateMinimumCollateral(); s.Offerer.FundPubKey = offer.PubKeys?.FundingKey; s.Offerer.PayoutDestination = offer.PubKeys?.PayoutAddress?.ScriptPubKey; s.FeeRate = offer.FeeRate; }
public DiscretePayoffs ToDiscretePayoffs(ContractInfo[] contractInfo) { if (contractInfo is null || contractInfo.Length is 0) { throw new ArgumentException("contractInfo is required", nameof(contractInfo)); } DiscretePayoffs payoffs = new DiscretePayoffs(); foreach (var ci in contractInfo) { payoffs.Add(new DiscretePayoff(ci.Outcome, ci.Payout - TotalCollateral)); } return(payoffs); }
private DiscretePayoffs CreatePayoffs(List <string> payoffs) { var result = new DiscretePayoffs(); foreach (var payoff in payoffs) { if (!DiscretePayoff.TryParse(payoff, out var o) || o is null) { throw new CommandException("payoff", "The payoff can't be parsed"); } result.Add(o); } return(result); }
public void CanConvertContractInfoToPayoff() { var payoffs = new DiscretePayoffs(); payoffs.Add(new DiscreteOutcome("a"), Money.Coins(5.0m)); payoffs.Add(new DiscreteOutcome("b"), Money.Coins(-5.0m)); payoffs.Add(new DiscreteOutcome("c"), Money.Coins(-2.0m)); Assert.Equal(Money.Coins(5.0m), payoffs.CalculateMinimumCollateral()); var ci = payoffs.ToContractInfo(payoffs.CalculateMinimumCollateral()); Assert.Equal(Money.Coins(10.0m), ci[0].Payout); Assert.Equal(Money.Coins(0m), ci[1].Payout); Assert.Equal(Money.Coins(3.0m), ci[2].Payout); payoffs = DiscretePayoffs.CreateFromContractInfo(ci, Money.Coins(5.0m)); Assert.Equal(Money.Coins(5.0m), payoffs[0].Reward); Assert.Equal(Money.Coins(-5.0m), payoffs[1].Reward); Assert.Equal(Money.Coins(-2.0m), payoffs[2].Reward); }
public void FullExchange() { var offerExample = Parse <Messages.Offer>("Data/Offer2.json"); var offerKey = new Key(); var acceptKey = new Key(); var initiatorInputKey = new Key(); var acceptorInputKey = new Key(); var initiator = new DLCTransactionBuilder(true, null, null, null, Network.RegTest); var requiredFund = initiator.Offer(offerExample.OracleInfo.PubKey, offerExample.OracleInfo.RValue, DiscretePayoffs.CreateFromContractInfo(offerExample.ContractInfo, offerExample.TotalCollateral, new[] { new DiscreteOutcome("Republicans_win"), new DiscreteOutcome("Democrats_win"), new DiscreteOutcome("other") }), offerExample.Timeouts); var fund1 = GetFundingPSBT(initiatorInputKey, requiredFund); var offer = initiator.FundOffer(offerKey, fund1); var acceptor = new DLCTransactionBuilder(false, null, null, null, Network.RegTest); var acceptorPayoff = acceptor.Accept(offer); var fund2 = GetFundingPSBT(acceptorInputKey, acceptorPayoff.CalculateMinimumCollateral()); var accept = acceptor.FundAccept(acceptKey, fund2); initiator.Sign1(accept); var fundPSBT = initiator.GetFundingPSBT(); fundPSBT.SignWithKeys(initiatorInputKey); var sign = initiator.Sign2(offerKey, fundPSBT); acceptor.Finalize1(sign); fundPSBT = acceptor.GetFundingPSBT(); fundPSBT.SignWithKeys(acceptorInputKey); var fullyVerified = acceptor.Finalize(fundPSBT); foreach (var i in fullyVerified.Inputs) { Assert.NotNull(i.WitScript); } fundPSBT = acceptor.GetFundingPSBT(); if (fundPSBT.TryGetEstimatedFeeRate(out var estimated)) { Assert.True(estimated > new FeeRate(1.0m), "Fee Rate of the funding PSBT are too low"); } }