Exemple #1
0
        public async Task <bool> AddEvent(EventFullName name, SchnorrNonce nonce, string[] outcomes, RootedKeyPath?nonceKeyPath = null)
        {
            var oracle = await GetOracle(name.OracleName);

            if (oracle is null)
            {
                throw new InvalidOperationException("The oracle does not exists");
            }
            var events = await GetEvents(oracle);

            var evt = GetEvent(name, events);

            if (evt is Event)
            {
                return(false);
            }
            evt = new Event()
            {
                Name         = name.Name,
                Nonce        = nonce,
                Outcomes     = outcomes,
                NonceKeyPath = nonceKeyPath
            };
            events.Add(evt);
            await SaveEvents(oracle, events);

            return(true);
        }
Exemple #2
0
        public async Task <Event?> TryGetEvent(EventFullName eventFullName)
        {
            var id = await NameRepository.AsEventRepository().GetEventId(eventFullName);

            if (id is null)
            {
                return(null);
            }
            return(await Repository.GetEvent(id));
        }
Exemple #3
0
        public async Task <Event> GetEvent(string optionName, EventFullName eventFullName)
        {
            var evt = await TryGetEvent(eventFullName);

            if (evt is null)
            {
                throw new CommandException(optionName, "This event's full name does not exists");
            }
            return(evt);
        }
Exemple #4
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");
            }
            if (await this.TryGetDLC(name) != null)
            {
                throw new CommandException("name", "This DLC already exists");
            }
            EventFullName evtName = context.GetEventName();
            var           oracle  = await GetOracle("eventfullname", evtName.OracleName);

            if (oracle?.PubKey is null)
            {
                throw new CommandException("eventfullname", "The specified oracle does not exists");
            }
            var evt = await GetEvent("eventfullname", evtName);

            var payoffsStr = context.ParseResult.CommandResult.GetArgumentValueOrDefault <List <string> >("payoff");

            if (payoffsStr is null || payoffsStr.Count == 0)
            {
                throw new CommandOptionRequiredException("payoff");
            }
            var payoffs = CreatePayoffs(payoffsStr);

            FixCasing(evt, payoffs);
            var builder = new DLCTransactionBuilder(true, null, null, null, Network);

            var timeout = new Timeouts()
            {
                ContractMaturity = 0,
                ContractTimeout  = Constants.NeverLockTime
            };

            if (context.ParseResult.HasOption("cetlocktime"))
            {
                timeout.ContractMaturity = new LockTime(context.ParseResult.ValueForOption <uint>("cetlocktime"));
            }
            if (context.ParseResult.HasOption("refundlocktime"))
            {
                timeout.ContractTimeout = new LockTime(context.ParseResult.ValueForOption <uint>("refundlocktime"));
            }
            var collateral = payoffs.CalculateMinimumCollateral();

            builder.Offer(oracle.PubKey, evt.EventId !.RValue, payoffs, timeout);
            var dlc = await Repository.NewDLC(evt.EventId, builder);

            await NameRepository.AsDLCNameRepository().SetMapping(name, dlc.LocalId);

            context.Console.Out.Write($"Offer created, you now need to setup the DLC sending {collateral} BTC to yourself. For more information, run `dlc show \"{name}\"`.");
        }
Exemple #5
0
        public async Task <Event?> GetEvent(EventFullName evtName)
        {
            var oracle = await GetOracle(evtName.OracleName);

            if (oracle is null)
            {
                return(null);
            }
            var evts = await GetEvents(oracle);

            return(evts.FirstOrDefault(e => e.Name.Equals(evtName.Name, StringComparison.OrdinalIgnoreCase)));
        }
        public async Task <OracleInfo?> GetEventId(EventFullName eventFullName)
        {
            var oracleId = await NameRepository.AsOracleNameRepository().GetId(eventFullName.OracleName);

            if (oracleId is null)
            {
                return(null);
            }
            var id = await NameRepository.GetId(Scopes.Events, GetEventFullName(oracleId, eventFullName.Name));

            if (id is null)
            {
                return(null);
            }
            if (!SchnorrNonce.TryParse(id, out var nonce))
            {
                return(null);
            }
            return(new OracleInfo(oracleId.PubKey, nonce));
        }
Exemple #7
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?.BuilderState is null ||
                dlc?.OracleInfo is null)
            {
                throw new CommandException("name", "This DLC does not exist");
            }

            var oracle = await Repository.GetOracle(dlc.OracleInfo.PubKey);

            string?oracleName = null;

            EventFullName eventName = new EventFullName("???", "???");

            if (oracle != null)
            {
                oracleName = await NameRepository.GetName(Scopes.Oracles, new OracleId(dlc.OracleInfo.PubKey).ToString());

                var ev = await Repository.GetEvent(dlc.OracleInfo);

                eventName = await NameRepository.AsEventRepository().ResolveName(dlc.OracleInfo) ?? eventName;
            }
            var shown = ParseShownItem(context);

            if (shown == ShowOption.DLC)
            {
                context.Console.Out.WriteLine($"Name: {name}");
                context.Console.Out.WriteLine($"Local Id: {dlc.Id}");
                var builder = new DLCTransactionBuilder(dlc.BuilderState.ToString(), Network);
                var role    = builder.State.IsInitiator ? "Offerer" : "Acceptor";
                context.Console.Out.WriteLine($"Event: {eventName}");
                context.Console.Out.WriteLine($"Role: {role}");
                var nextStep = dlc.GetNextStep(Network);
                context.Console.Out.WriteLine($"Next step: {nextStep}");
                context.Console.Out.WriteLine($"Next step explanation:");
                context.Console.Out.Write($"{Explain(nextStep, name, builder.State)}");
            }
            else if (shown == ShowOption.Offer)
            {
                if (dlc.Offer is null)
                {
                    throw new CommandException("offer", "No offer available for this DLC");
                }
                context.WriteObject(dlc.Offer, Repository.JsonSettings);
            }
            else if (shown == ShowOption.Accept)
            {
                if (dlc.Accept is null)
                {
                    throw new CommandException("offer", "No accept message available for this DLC");
                }
                context.WriteObject(dlc.Accept, Repository.JsonSettings);
            }
            else if (shown == ShowOption.Funding)
            {
                try
                {
                    var builder = new DLCTransactionBuilder(dlc.BuilderState.ToString(), Network);
                    context.WritePSBT(builder.GetFundingPSBT());
                }
                catch
                {
                    throw new CommandException("funding", "No funding PSBT ready for this DLC");
                }
            }
            else if (shown == ShowOption.Abort)
            {
                if (dlc.Abort is null)
                {
                    throw new CommandException("abort", "No abort PSBT for this DLC");
                }
                context.WritePSBT(dlc.Abort);
            }
            else if (shown == ShowOption.Refund)
            {
                try
                {
                    var builder = new DLCTransactionBuilder(dlc.BuilderState.ToString(), Network);
                    context.WriteTransaction(builder.BuildRefund(), Network);
                }
                catch
                {
                    throw new CommandException("refund", "No refund PSBT ready for this DLC");
                }
            }
            else
            {
                throw new NotSupportedException();
            }
        }
Exemple #8
0
 private static Event GetEvent(EventFullName name, List <Event> events)
 {
     return(events.FirstOrDefault(ev => ev.Name?.Equals(name.Name, StringComparison.OrdinalIgnoreCase) is true));
 }
Exemple #9
0
        public async Task <DiscreteOutcome?> AddAttestation(EventFullName name, Key oracleAttestation)
        {
            var oracles = await GetOracles();

            var oracle = GetOracle(name.OracleName, oracles);

            if (oracle?.PubKey is null)
            {
                return(null);
            }
            var events = await GetEvents(oracle);

            var evt = events.FirstOrDefault(e => e.Name.Equals(name.Name, StringComparison.OrdinalIgnoreCase));

            if (evt?.Nonce is null)
            {
                return(null);
            }
            var attestation = oracleAttestation.ToECPrivKey();
            var sig         = evt.Nonce.CreateSchnorrSignature(attestation);

            if (sig is null)
            {
                return(null);
            }
            foreach (var outcome in evt.Outcomes)
            {
                var discreteOutcome = new DiscreteOutcome(outcome);
                if (!oracle.PubKey.SigVerifyBIP340(sig, discreteOutcome.Hash))
                {
                    continue;
                }
                evt.Attestations ??= new Dictionary <string, Key>();
                if (!evt.Attestations.TryAdd(outcome, oracleAttestation))
                {
                    return(null);
                }
                // If we have two attestation for the same event, we can recover the private
                // key of the oracle
                if (evt.Attestations.Count > 1 && oracle.RootedKeyPath is null)
                {
                    var sigs = evt.Attestations.Select(kv => (Outcome: new DiscreteOutcome(kv.Key),
                                                              Signature: evt.Nonce.CreateSchnorrSignature(kv.Value.ToECPrivKey()) ?? throw new InvalidOperationException("Invalid signature in attestations")))
                               .Take(2)
                               .ToArray();
                    if (!oracle.PubKey.TryExtractPrivateKey(
                            sigs[0].Outcome.Hash, sigs[0].Signature,
                            sigs[1].Outcome.Hash, sigs[1].Signature, out var extracted) || extracted is null)
                    {
                        throw new InvalidOperationException("Could not recover the private key of the oracle, this should never happen");
                    }
                    var k = new Key(extracted.ToBytes());
                    oracle.RootedKeyPath = new RootedKeyPath(k.PubKey.GetHDFingerPrint(), new KeyPath());
                    await SaveOracles(oracles);

                    if (!KeySetExists(k.PubKey.GetHDFingerPrint()))
                    {
                        await SaveKeyset(k.PubKey.GetHDFingerPrint(), new Keyset()
                        {
                            SingleKey = k
                        });
                    }
                }
                await SaveEvents(oracle, events);

                return(discreteOutcome);
            }
            return(null);
        }