public async Task <bool> AutoFillAsync( IKeyStorage keyStorage, WalletAddress address, bool useDefaultFee) { var xtz = (Atomex.Tezos)Currency; if (address.KeyIndex == null) { Log.Error("Can't find private key for address {@address}", address); return(false); } using var securePrivateKey = keyStorage .GetPrivateKey(Currency, address.KeyIndex); if (securePrivateKey == null) { Log.Error("Can't find private key for address {@address}", address); return(false); } using var privateKey = securePrivateKey.ToUnsecuredBytes(); using var securePublicKey = keyStorage .GetPublicKey(Currency, address.KeyIndex); using var publicKey = securePublicKey.ToUnsecuredBytes(); var rpc = new Rpc(xtz.RpcNodeUri); Head = await rpc .GetHeader() .ConfigureAwait(false); var managerKey = await rpc .GetManagerKey(From) .ConfigureAwait(false); Operations = new JArray(); var gas = GasLimit.ToString(CultureInfo.InvariantCulture); var storage = StorageLimit.ToString(CultureInfo.InvariantCulture); var counter = await TezosCounter.Instance .GetCounter(xtz, From, Head, ignoreCache : true) .ConfigureAwait(false); if (managerKey.Value <string>() == null) { //var revealOpCounter = await TezosCounter.Instance // .GetCounter(xtz, From, Head, ignoreCache: true) // .ConfigureAwait(false); var revealOp = new JObject { ["kind"] = OperationType.Reveal, ["fee"] = "0", ["public_key"] = Base58Check.Encode(publicKey, Prefix.Edpk), ["source"] = From, ["storage_limit"] = storage, ["gas_limit"] = gas, ["counter"] = counter.ToString()//revealOpCounter.ToString() }; Operations.AddFirst(revealOp); counter++; } //var counter = await TezosCounter.Instance // .GetCounter(xtz, From, Head) // .ConfigureAwait(false); var transaction = new JObject { ["kind"] = OperationType.Delegation, ["source"] = From, ["fee"] = ((int)Fee).ToString(CultureInfo.InvariantCulture), ["counter"] = counter.ToString(), ["gas_limit"] = gas, ["storage_limit"] = storage, ["delegate"] = To }; Operations.Add(transaction); if (Params != null) { transaction["parameters"] = Params; } var fill = await rpc .AutoFillOperations(xtz, Head, Operations, useDefaultFee) .ConfigureAwait(false); if (!fill) { Log.Error("Delegation autofilling error"); return(false); } // Fee = Operations[0]["fee"].Value<decimal>() / 1_000_000; Fee = Operations.Last["fee"].Value <decimal>() / 1_000_000; return(true); }
public async Task <(bool result, bool isRunSuccess, bool hasReveal)> FillOperationsAsync( SecureBytes securePublicKey, TezosConfig tezosConfig, int headOffset = 0, bool isAlreadyRevealed = false, CancellationToken cancellationToken = default) { using var publicKey = securePublicKey.ToUnsecuredBytes(); var rpc = new Rpc(tezosConfig.RpcNodeUri); var managerKey = await rpc .GetManagerKey(From) .ConfigureAwait(false); var actualHead = await rpc .GetHeader() .ConfigureAwait(false); if (Head == null) { Head = await rpc .GetHeader(headOffset) .ConfigureAwait(false); } Operations = new JArray(); var gas = GasLimit.ToString(CultureInfo.InvariantCulture); var storage = StorageLimit.ToString(CultureInfo.InvariantCulture); var revealed = managerKey.Value <string>() != null || isAlreadyRevealed; UsedCounters = revealed ? 1 : 2; var counter = UseOfflineCounter ? await TezosCounter.Instance .GetOfflineCounterAsync( address : From, head : actualHead["hash"].ToString(), rpcNodeUri : tezosConfig.RpcNodeUri, numberOfCounters : UsedCounters) .ConfigureAwait(false) : await TezosCounter.Instance .GetCounterAsync( address : From, head : actualHead["hash"].ToString(), rpcNodeUri : tezosConfig.RpcNodeUri) .ConfigureAwait(false); if (!revealed) { var revealOp = new JObject { ["kind"] = Internal.OperationType.Reveal, ["fee"] = "0", ["public_key"] = Base58Check.Encode(publicKey, Prefix.Edpk), ["source"] = From, ["storage_limit"] = "0", ["gas_limit"] = tezosConfig.RevealGasLimit.ToString(), ["counter"] = counter.ToString() }; Operations.AddFirst(revealOp); counter++; } var operation = new JObject { ["kind"] = OperationType, ["source"] = From, ["fee"] = ((int)Fee).ToString(CultureInfo.InvariantCulture), ["counter"] = counter.ToString(), ["gas_limit"] = gas, ["storage_limit"] = storage, }; if (OperationType == Internal.OperationType.Transaction) { operation["amount"] = Math.Round(Amount, 0).ToString(CultureInfo.InvariantCulture); operation["destination"] = To; } else if (OperationType == Internal.OperationType.Delegation) { operation["delegate"] = To; } else { throw new NotSupportedException($"Operation type {OperationType} not supporeted yet."); } Operations.Add(operation); if (Params != null) { operation["parameters"] = Params; } var isRunSuccess = false; if (UseRun) { var fill = await rpc .AutoFillOperations(tezosConfig, Head, Operations, UseSafeStorageLimit) .ConfigureAwait(false); if (!fill) { Log.Warning("Operation autofilling error"); } else { Fee = Operations.Last["fee"].Value <decimal>().ToTez(); isRunSuccess = true; } } return( result : true, isRunSuccess : isRunSuccess, hasReveal : !revealed ); }
public async Task <bool> SignAsync( IKeyStorage keyStorage, WalletAddress address, CancellationToken cancellationToken = default) { var xtz = (Atomex.Tezos)Currency; if (address.KeyIndex == null) { Log.Error("Can't find private key for address {@address}", address); return(false); } using var securePrivateKey = keyStorage .GetPrivateKey(Currency, address.KeyIndex); if (securePrivateKey == null) { Log.Error("Can't find private key for address {@address}", address); return(false); } using var privateKey = securePrivateKey.ToUnsecuredBytes(); using var securePublicKey = keyStorage .GetPublicKey(Currency, address.KeyIndex); var rpc = new Rpc(xtz.RpcNodeUri); Head = await rpc .GetHeader() .ConfigureAwait(false); await FillOperationsAsync(Head, securePublicKey) .ConfigureAwait(false); if (Type != BlockchainTransactionType.Output) { UseDefaultFee = true; } var fill = await rpc .AutoFillOperations(xtz, Head, Operations, UseDefaultFee) .ConfigureAwait(false); if (!fill) { Log.Error("Transaction autofilling error"); return(false); } // todo: update Fee, GasLimit, StorageLimit var forgedOpGroup = await rpc .ForgeOperations(Head, Operations) .ConfigureAwait(false); var forgedOpGroupLocal = Forge.ForgeOperationsLocal(Head, Operations); //if (true) //if (config.CheckForge == true) add option for higher security tezos mode to config //{ // if (forgedOpGroupLocal.ToString() != forgedOpGroup.ToString()) // { // Log.Error("Local and remote forge results differ"); // return false; // } //} SignedMessage = TezosSigner.SignHash( data: Hex.FromString(forgedOpGroup.ToString()), privateKey: privateKey, watermark: Watermark.Generic, isExtendedKey: privateKey.Length == 64); return(true); }