protected override async Task InvokeAsyncBase(InvocationContext context) { var name = context.ParseResult.CommandResult.GetArgumentValueOrDefault <string>("name")?.Trim(); if (name is null) { throw new CommandOptionRequiredException("name"); } var dlc = await GetDLC("name", name); if (dlc is null) { throw new CommandException("name", "This DLC does not exist"); } var psbt = context.ParsePSBT("setuppsbt", Network); var builder = dlc.GetBuilder(Network); if (builder.State.IsInitiator) { context.AssertState("name", dlc, true, DLCNextStep.Setup, Network); var key = await Repository.CreatePrivateKey(); try { var offer = builder.FundOffer(key.PrivateKey, psbt); dlc.FundKeyPath = key.KeyPath; dlc.Abort = psbt; dlc.BuilderState = builder.ExportStateJObject(); dlc.Offer = offer; await Repository.AddAliasId(dlc.LocalId, offer.GetTemporaryContractId()); await Repository.SaveDLC(dlc); context.WriteObject(offer, Repository.JsonSettings); } catch (InvalidOperationException err) { throw new CommandException("fundpsbt", err.Message); } } else { context.AssertState("name", dlc, false, DLCNextStep.Setup, Network); var k = await Repository.CreatePrivateKey(); var accept = builder.FundAccept(k.PrivateKey, psbt); dlc.FundKeyPath = k.KeyPath; dlc.Abort = psbt; dlc.BuilderState = builder.ExportStateJObject(); dlc.Accept = accept; if (builder.State.ContractId is null) { throw new InvalidOperationException("ContractId should be known by now"); } await Repository.AddAliasId(dlc.LocalId, builder.State.ContractId); await Repository.SaveDLC(dlc); context.WriteObject(accept, Repository.JsonSettings); } }
protected override async Task InvokeAsyncBase(InvocationContext context) { var offer = DLCHelpers.GetOffer(context, Network); var name = context.ParseResult.CommandResult.GetArgumentValueOrDefault <string>("name")?.Trim(); if (name is null) { throw new CommandOptionRequiredException("name"); } if (await this.TryGetDLC(name) != null) { throw new CommandException("name", "This DLC already exists"); } if (offer.OracleInfo is null) { throw new CommandException("offer", "Missing oracleInfo"); } if (offer.Timeouts is null) { throw new CommandException("offer", "Missing timeouts"); } if (offer.ContractInfo is null) { throw new CommandException("offer", "Missing contractInfos"); } var oracle = await Repository.GetOracle(offer.OracleInfo.PubKey); if (oracle is null) { throw new CommandException("offer", "Unknown oracle"); } var evt = await Repository.GetEvent(offer.OracleInfo.PubKey, offer.OracleInfo.RValue); if (evt is null) { throw new CommandException("offer", "Unknown event"); } var maturity = new LockTimeEstimation(offer.Timeouts.ContractMaturity, Network); var refund = new LockTimeEstimation(offer.Timeouts.ContractTimeout, Network); if (!refund.UnknownEstimation) { if (refund.EstimatedRemainingBlocks == 0) { throw new CommandException("offer", "The refund should not be immediately valid"); } if (refund.EstimatedRemainingBlocks < maturity.EstimatedRemainingBlocks) { throw new CommandException("offer", "The refund should not be valid faster than the contract execution transactions"); } } offer.SetContractPreimages(evt.Outcomes); try { var builder = new DLCTransactionBuilder(false, null, null, null, Network); builder.Accept(offer); var collateral = offer.ToDiscretePayoffs(offer.ContractInfo).Inverse().CalculateMinimumCollateral(); var dlc = await Repository.NewDLC(offer.OracleInfo, builder); dlc.BuilderState = builder.ExportStateJObject(); dlc.Offer = offer; await NameRepository.AsDLCNameRepository().SetMapping(name, dlc.LocalId); await Repository.AddAliasId(dlc.LocalId, offer.GetTemporaryContractId()); await Repository.SaveDLC(dlc); context.Console.Out.Write($"Contract accepted, you now need to setup the DLC sending {collateral} BTC to yourself. For more information, run `dlc show \"{name}\"`."); } catch (Exception ex) { throw new CommandException("offer", $"Invalid offer or PSBT. ({ex.Message})"); } }