public void DecryptNEP2() { var passphrase = "Satoshi"; var encrypted = "6PYN6mjwYfjPUuYT3Exajvx25UddFVLpCw4bMsmtLdnKwZ9t1Mi3CfKe8S"; var keys = NeoKeys.FromNEP2(encrypted, passphrase); var wif = keys.WIF; var expectedWIF = "KwYgW8gcxj1JWJXhPSu4Fqwzfhp5Yfi42mdYmMa4XqK7NJxXUSK7"; Assert.IsTrue(expectedWIF == wif); }
public async Task <object> InvokeSettleTx(NeoKeys neoKeys, PhantasmaKeys phantasmaKeys, string txHash, string symbol) { try { Hash neoTxHash = Hash.Parse(txHash); var transcodedAddress = Address.FromKey(neoKeys); var script = ScriptUtils.BeginScript() .CallContract("interop", "SettleTransaction", transcodedAddress, NeoWallet.NeoPlatform, NeoWallet.NeoPlatform, neoTxHash) .CallContract("swap", "SwapFee", transcodedAddress, symbol, UnitConversion.ToBigInteger(0.1m, DomainSettings.FuelTokenDecimals)) .TransferBalance(symbol, transcodedAddress, phantasmaKeys.Address) .AllowGas(transcodedAddress, Address.Null, MinimumFee, 800) .SpendGas(transcodedAddress) .EndScript(); var nexusName = WalletConfig.Network; var tx = new Phantasma.Blockchain.Transaction(nexusName, "main", script, DateTime.UtcNow + TimeSpan.FromMinutes(30), "PHT-0-8-7"); tx.Sign(neoKeys); var txResult = await _phantasmaRpcService.SendRawTx.SendRequestAsync(tx.ToByteArray(true).Encode()); Log.Information("txResult: " + txResult); return(txResult); } catch (RpcResponseException rpcEx) { Log.Error($"RPC Exception occurred: {rpcEx.RpcError.Message}"); return(new ErrorRes { error = rpcEx.RpcError.Message }); } catch (Exception ex) { Log.Error($"Exception occurred: {ex.Message}"); return(new ErrorRes { error = ex.Message }); } }
private static Hash NeoTransfer(NeoKeys neoKeys, string toAddress, string tokenSymbol, decimal tempAmount, NeoAPI neoAPI) { Neo.Core.Transaction neoTx; logger.Message($"Sending {tempAmount} {tokenSymbol} to {toAddress}..."); Thread.Sleep(500); try { if (tokenSymbol == "NEO" || tokenSymbol == "GAS") { neoTx = neoAPI.SendAsset(neoKeys, toAddress, tokenSymbol, tempAmount, out string usedRpc); } else { var nep5 = neoAPI.GetToken(tokenSymbol); if (nep5 == null) { throw new CommandException($"Could not find interface for NEP5: {tokenSymbol}"); } neoTx = nep5.Transfer(neoKeys, toAddress, tempAmount); } logger.Success($"Waiting for confirmations, could take up to a minute..."); Thread.Sleep(45000); logger.Success($"Sent transaction with hash {neoTx.Hash}!"); var hash = Hash.Parse(neoTx.Hash.ToString()); return(hash); } catch (Exception e) { logger.Message("Error sending NEO transaction: " + e); return(Hash.Null); } }
public InteropTransaction ReadTransaction(Hash hash) { var hashText = hash.ToString(); var apiCall = $"get_transaction/{hashText}"; var json = ExecuteRequest(apiCall); if (json == null) { throw new OracleException("Network read failure: " + apiCall); } string inputSource = null; try { var root = JSONReader.ReadFromString(json); var scripts = root.GetNode("scripts"); Throw.IfNull(scripts, nameof(scripts)); if (scripts.ChildCount != 1) { throw new OracleException("Transactions with multiple sources not supported yet"); } Address interopAddress = Address.Null; foreach (var scriptEntry in scripts.Children) { var vs = scriptEntry.GetNode("verification"); if (vs == null) { continue; } var verificationScript = Base16.Decode(vs.Value); var pubKey = new byte[33]; Core.Utils.ByteArrayUtils.CopyBytes(verificationScript, 1, pubKey, 0, 33); var signatureScript = NeoKeys.CreateSignatureScript(pubKey); var signatureHash = Neo.Utils.CryptoUtils.ToScriptHash(signatureScript); inputSource = Neo.Utils.CryptoUtils.ToAddress(signatureHash); pubKey = Core.Utils.ByteArrayUtils.ConcatBytes((byte)AddressKind.User, pubKey); interopAddress = Address.FromBytes(pubKey); break; } if (interopAddress.IsNull) { throw new OracleException("Could not fetch public key from transaction"); } if (string.IsNullOrEmpty(inputSource)) { throw new OracleException("Could not fetch source address from transaction"); } var attrNodes = root.GetNode("attributes"); if (attrNodes != null) { foreach (var entry in attrNodes.Children) { var kind = entry.GetString("usage"); if (kind == "Description") { var data = entry.GetString("data"); var bytes = Base16.Decode(data); var text = Encoding.UTF8.GetString(bytes); if (Address.IsValidAddress(text)) { interopAddress = Address.FromText(text); } } } } return(FillTransaction(hashText, inputSource, interopAddress)); } catch (Exception e) { throw new OracleException(e.Message); } }
// NOTE no locks happen here because this callback is called from within a lock internal override Hash SettleSwap(Hash sourceHash, Address destination, IToken token, Numerics.BigInteger amount) { Hash txHash = Hash.Null; string txStr = null; var inProgressMap = new StorageMap(TokenSwapper.InProgressTag, Swapper.Storage); var rpcMap = new StorageMap(TokenSwapper.UsedRpcTag, Swapper.Storage); if (inProgressMap.ContainsKey <Hash>(sourceHash)) { txStr = inProgressMap.Get <Hash, string>(sourceHash); if (!string.IsNullOrEmpty(txStr)) { return(VerifyNeoTx(sourceHash, txStr)); } } var total = Numerics.UnitConversion.ToDecimal(amount, token.Decimals); var neoKeys = NeoKeys.FromWIF(this.WIF); var destAddress = NeoWallet.DecodeAddress(destination); Logger.Debug($"NEOSWAP: Trying transfer of {total} {token.Symbol} from {neoKeys.Address} to {destAddress}"); var nonce = sourceHash.ToByteArray(); Neo.Core.Transaction tx = null; string usedRpc = null; try { if (token.Symbol == "NEO" || token.Symbol == "GAS") { tx = neoAPI.SendAsset(neoKeys, destAddress, token.Symbol, total, out usedRpc); } else { var nep5 = neoAPI.GetToken(token.Symbol); tx = nep5.Transfer(neoKeys, destAddress, total, nonce, x => usedRpc = x); } // persist resulting tx hash as in progress inProgressMap.Set <Hash, string>(sourceHash, tx.Hash.ToString()); rpcMap.Set <Hash, string>(sourceHash, usedRpc); Logger.Debug("broadcasted neo tx: " + tx); } catch (Exception e) { Logger.Error("Error during transfering {token.Symbol}: " + e); return(Hash.Null); } if (tx == null) { Logger.Error($"NeoAPI error {neoAPI.LastError} or possible failed neo swap sourceHash: {sourceHash} no transfer happend."); return(Hash.Null); } var strHash = tx.Hash.ToString(); return(VerifyNeoTx(sourceHash, strHash)); }
public static void Transfer(SpookSettings settings, NexusAPI api, BigInteger minimumFee, NeoAPI neoAPI, string[] args) { if (args.Length != 4) { throw new CommandException("Expected args: source_address target_address amount symbol"); } DoChecks(api); var tempAmount = decimal.Parse(args[2]); var tokenSymbol = args[3]; var tokenInfo = FetchTokenInfo(api, tokenSymbol); if (!tokenInfo.flags.Contains("Fungible")) { throw new CommandException("Token must be fungible!"); } var amount = UnitConversion.ToBigInteger(tempAmount, tokenInfo.decimals); var sourceName = args[0]; string sourcePlatform; if (Address.IsValidAddress(sourceName)) { sourcePlatform = PhantasmaWallet.PhantasmaPlatform; } else if (NeoWallet.IsValidAddress(sourceName)) { sourcePlatform = NeoWallet.NeoPlatform; } else { throw new CommandException("Invalid source address " + sourceName); } var destName = args[1]; string destPlatform; if (Address.IsValidAddress(destName)) { destPlatform = PhantasmaWallet.PhantasmaPlatform; } else if (NeoWallet.IsValidAddress(destName)) { destPlatform = NeoWallet.NeoPlatform; } else { throw new CommandException("Invalid destination address " + destName); } if (destName == sourceName) { throw new CommandException("Cannot transfer to same address"); } if (sourcePlatform != PhantasmaWallet.PhantasmaPlatform) { if (destPlatform != PhantasmaWallet.PhantasmaPlatform) { if (sourcePlatform != destPlatform) { throw new CommandException($"Cannot transfer directly from {sourcePlatform} to {destPlatform}"); } else { switch (destPlatform) { case NeoWallet.NeoPlatform: { var neoKeys = new NeoKeys(Keys.PrivateKey); if (sourceName != neoKeys.Address) { throw new CommandException("The current open wallet does not have keys that match address " + sourceName); } var neoHash = NeoTransfer(neoKeys, destName, tokenSymbol, tempAmount, neoAPI); return; } default: throw new CommandException($"Not implemented yet :("); } } } else { logger.Message($"Source is {sourcePlatform} address, a swap will be performed using an interop address."); IPlatform platformInfo = api.Nexus.GetPlatformInfo(api.Nexus.RootStorage, sourcePlatform); Hash extHash; IKeyPair extKeys; switch (sourcePlatform) { case NeoWallet.NeoPlatform: { try { var neoKeys = new NeoKeys(Keys.PrivateKey); if (sourceName != neoKeys.Address) { throw new CommandException("The current open wallet does not have keys that match address " + sourceName); } extHash = NeoTransfer(neoKeys, platformInfo.InteropAddresses[0].ExternalAddress, tokenSymbol, tempAmount, neoAPI); if (extHash == Hash.Null) { return; } extKeys = neoKeys; } catch (Exception e) { logger.Message($"{sourcePlatform} error: " + e.Message); return; } break; } default: logger.Message($"Transactions using platform {sourcePlatform} are not supported yet"); return; } var destAddress = Address.FromText(destName); SettleSwap(settings, api, minimumFee, sourcePlatform, tokenSymbol, extHash, extKeys, destAddress); } return; } else { Address destAddress; if (destPlatform != PhantasmaWallet.PhantasmaPlatform) { switch (destPlatform) { case NeoWallet.NeoPlatform: destAddress = NeoWallet.EncodeAddress(destName); break; default: logger.Message($"Transactions to platform {destPlatform} are not supported yet"); return; } logger.Message($"Target is {destPlatform} address, a swap will be performed through interop address {destAddress}."); } else { destAddress = Address.FromText(destName); } var script = ScriptUtils.BeginScript(). CallContract("swap", "SwapFee", Keys.Address, tokenSymbol, UnitConversion.ToBigInteger(0.01m, DomainSettings.FuelTokenDecimals)). AllowGas(Keys.Address, Address.Null, minimumFee, 9999). TransferTokens(tokenSymbol, Keys.Address, destAddress, amount). SpendGas(Keys.Address). EndScript(); logger.Message($"Sending {tempAmount} {tokenSymbol} to {destAddress.Text}..."); ExecuteTransaction(settings, api, script, ProofOfWork.None, Keys); } }