Example #1
0
        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);
            }
        }
Example #2
0
        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})");
            }
        }