private InteropTransaction FillTransaction(string hashText, string inputAddress, Address interopAddress) { int page = 1; int maxPages = 9999; while (page <= maxPages) { var apiCall = $"get_address_abstracts/{inputAddress}/{page}"; var json = ExecuteRequest(apiCall); if (json == null) { throw new OracleException("Network read failure: " + apiCall); } var root = JSONReader.ReadFromString(json); var entries = root.GetNode("entries"); for (int i = 0; i < entries.ChildCount; i++) { var entry = entries.GetNodeByIndex(i); var txId = entry.GetString("txid"); if (hashText.Equals(txId, StringComparison.OrdinalIgnoreCase)) { var inputAsset = entry.GetString("asset"); var symbol = FindSymbolFromAsset(inputAsset); if (symbol == null) { throw new OracleException("transaction contains unknown asset: " + inputAsset); } var inputAmount = entry.GetDecimal("amount"); var sourceAddress = entry.GetString("address_from"); var destAddress = entry.GetString("address_to"); var info = nexus.GetTokenInfo(nexus.RootStorage, symbol); var amount = UnitConversion.ToBigInteger(inputAmount, info.Decimals); var txHash = Hash.Parse(hashText); var tx = new InteropTransaction(txHash, new InteropTransfer[] { new InteropTransfer("neo", NeoWallet.EncodeAddress(sourceAddress), "neo", NeoWallet.EncodeAddress(destAddress), interopAddress, symbol, amount) }); return(tx); } } page++; } throw new Exception("could not fill oracle transaction: " + hashText); }
protected void OnPlatformAddressAdd(string[] args) { var platform = args[0]; var externalAddress = args[1]; Address localAddress; switch (platform) { case NeoWallet.NeoPlatform: localAddress = NeoWallet.EncodeAddress(externalAddress); break; case EthereumWallet.EthereumPlatform: localAddress = EthereumWallet.EncodeAddress(externalAddress); break; case BSCWallet.BSCPlatform: localAddress = BSCWallet.EncodeAddress(externalAddress); break; default: throw new Exception("Unknown platform: " + platform); } var minimumFee = _cli.Settings.Node.MinimumFee; var script = ScriptUtils.BeginScript() .AllowGas(_cli.NodeKeys.Address, Address.Null, minimumFee, 1500) .CallContract("interop", nameof(InteropContract.RegisterAddress), _cli.NodeKeys.Address, platform, localAddress, externalAddress) .SpendGas(_cli.NodeKeys.Address).EndScript(); var expire = Timestamp.Now + TimeSpan.FromMinutes(2); var tx = new Phantasma.Blockchain.Transaction(_cli.Nexus.Name, _cli.Nexus.RootChain.Name, script, expire, Spook.TxIdentifier); tx.Mine((int)ProofOfWork.Minimal); tx.Sign(_cli.NodeKeys); if (_cli.Mempool != null) { _cli.Mempool.Submit(tx); Console.WriteLine($"Transaction {tx.Hash} submitted to mempool."); } else { Console.WriteLine("No mempool available"); return; } Console.WriteLine($"Added address {externalAddress} to {platform}"); Spook.Logger.Message($"Added address {externalAddress} to {platform}"); }
public static Address EncodeAddress(string source, string chainName) { switch (chainName) { case NeoWallet.NeoPlatform: return(NeoWallet.EncodeAddress(source)); case EthereumWallet.EthereumPlatform: return(NeoWallet.EncodeAddress(source)); default: throw new NotImplementedException($"cannot encode addresses for {chainName} chain"); } }
void CreateWalletMethod(object obj) { if (((MainWindow)App.Current.MainWindow).ActiveDocument == null) { MessageBox.Show("Please create or open a Smart Contract.", "Neo Studio", MessageBoxButton.OK, MessageBoxImage.Error); return; } if (((MainWindow)App.Current.MainWindow).ActiveDocument.FilePath == null) { MessageBox.Show("Please save your Smart Contract.", "Neo Studio", MessageBoxButton.OK, MessageBoxImage.Error); return; } if (!string.IsNullOrEmpty(WalletName)) { if (App.WalletSettings.LocalWallets.Where(w => w.WalletName == Path.GetFileNameWithoutExtension(WalletName) + ".json").Count() > 0) { MessageBox.Show("Wallet Name Already exists...."); Messenger.Default.Send <bool>(true, "CloseCreateWalletWindow"); } string walletPath = Path.Combine(Path.GetDirectoryName(((MainWindow)App.Current.MainWindow).ActiveDocument.FilePath), Path.GetFileNameWithoutExtension(WalletName) + ".json");; LocalWallet localWallet; if (!NeoWallet.Create(walletPath, out localWallet)) { MessageBox.Show("Failed to create wallet", "Create Wallet", MessageBoxButton.OK, MessageBoxImage.Error); return; } App.WalletSettings.LocalWallets.Add(localWallet); App.WalletSettings.DefaultWallet = walletPath; App.WalletSettings.DefaultPassword = localWallet.Password; App.WalletSettings.Save(Path.GetDirectoryName(walletPath)); ((MainWindowViewModel)((NeoStudio.View.MainWindow)App.Current.MainWindow).DataContext).WalletList.Add(localWallet); ((MainWindowViewModel)((NeoStudio.View.MainWindow)App.Current.MainWindow).DataContext).SelectedWallet = localWallet; ((MainWindow)App.Current.MainWindow).RefreshSoltionExplorer(); MessageBox.Show("Success!!!", "Create Wallet", MessageBoxButton.OK, MessageBoxImage.Information); Messenger.Default.Send <bool>(true, "CloseCreateWalletWindow"); } else { MessageBox.Show("Please Enter a wallet Name."); } Messenger.Default.Send <bool>(true, "CloseCreateWalletWindow"); }
public void TestNeoWallet() { var keys = PhantasmaKeys.FromWIF("L1nuBmNJ2HvLat5xyvpqmHpmXNe6rGGdAzGJgLjDLECaTCVgqjdx"); var wallet = new NeoWallet(keys, "https://api.neoscan.io"); var address = wallet.Address; string expectedAddress = "AU2eYJkpZ2nG81RyqnzF5UL2qjdkpPEJqN"; Assert.IsTrue(address.Equals(expectedAddress, StringComparison.OrdinalIgnoreCase)); var encodedAddress = NeoWallet.EncodeAddress(expectedAddress); Assert.IsTrue(encodedAddress.IsInterop); var newAddress = NeoWallet.DecodeAddress(encodedAddress); Assert.IsTrue(newAddress.Equals(expectedAddress, StringComparison.OrdinalIgnoreCase)); }
public static void DecodePlatformAndAddress(Address source, out string platform, out string address) { byte[] bytes; source.DecodeInterop(out platform, out bytes, 0); switch (platform) { case NeoWallet.NeoPlatform: address = NeoWallet.DecodeAddress(source); break; case EthereumWallet.EthereumPlatform: address = EthereumWallet.DecodeAddress(source); break; default: throw new NotImplementedException($"cannot decode addresses for {platform} chain"); } }
// 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 InteropTransaction MakeInteropTx(Logger logger, NeoTx tx, NeoAPI api, string[] origSwapAddresses, string coldStorage) { logger.Debug("checking tx: " + tx.Hash); var swapAddresses = new List <Address>(); foreach (var addr in origSwapAddresses) { swapAddresses.Add(NeoWallet.EncodeAddress(addr)); } List <InteropTransfer> interopTransfers = new List <InteropTransfer>(); var emptyTx = new InteropTransaction(Hash.Null, interopTransfers.ToArray()); PBigInteger amount; var witness = tx.witnesses.ElementAtOrDefault(0); if (witness == null) { // tx has no witness return(emptyTx); } var interopAddress = witness.ExtractAddress(); if (tx.witnesses.Length != 1 || interopAddress == Address.Null || interopAddress == null) { //currently only one witness allowed // if ExtractAddress returns Address.Null, the tx is not properly signed return(emptyTx); } var sourceScriptHash = witness.verificationScript.Sha256().RIPEMD160(); var sourceAddress = NeoWallet.EncodeByteArray(sourceScriptHash); var sourceDecoded = NeoWallet.DecodeAddress(sourceAddress); if (sourceAddress == interopAddress || sourceDecoded == coldStorage) { logger.Warning("self send tx or cold storage transfer found, ignoring: " + tx.Hash); // self send, probably consolidation tx, ignore return(emptyTx); } //logger.Debug("interop address: " + interopAddress); //logger.Debug("xswapAddress: " + swapAddress); //logger.Debug("interop sourceAddress: " + sourceAddress); //logger.Debug("neo sourceAddress: " + NeoWallet.DecodeAddress(sourceAddress)); if (tx.attributes != null && tx.attributes.Length > 0) { foreach (var attr in tx.attributes) { if (attr.Usage == TransactionAttributeUsage.Description) { try { var text = Encoding.UTF8.GetString(attr.Data); if (Address.IsValidAddress(text)) { interopAddress = Address.FromText(text); //logger.Debug("new interop address: " + interopAddress); } } catch {} } } } if (tx.outputs.Length > 0) { foreach (var output in tx.outputs) { var targetAddress = NeoWallet.EncodeByteArray(output.scriptHash.ToArray()); //logger.Debug("interop targetAddress : " + targetAddress); //logger.Debug("neo targetAddress: " + NeoWallet.DecodeAddress(targetAddress)); //logger.Debug("interopSwapAddress: " + interopSwapAddress); //logger.Debug("targetAddress: " + targetAddress); //var swpAddress = NeoWallet.EncodeAddress(swapAddress); //logger.Debug("interop swpAddress: " + swpAddress); //logger.Debug("neo swpAddress: " + NeoWallet.DecodeAddress(swpAddress)); //if (targetAddress.ToString() == swapAddress) if (swapAddresses.Contains(targetAddress)) { var token = FindSymbolFromAsset(new UInt256(output.assetID).ToString()); CryptoCurrencyInfo tokenInfo; if (NeoTokenInfo.TryGetValue(token, out tokenInfo)) { amount = Phantasma.Numerics.UnitConversion.ToBigInteger( output.value, tokenInfo.Decimals); } else { // asset not swapable at the moment... //logger.Debug("Asset not swapable"); return(emptyTx); } //logger.Debug("UTXO " + amount); interopTransfers.Add ( new InteropTransfer ( NeoWallet.NeoPlatform, sourceAddress, DomainSettings.PlatformName, targetAddress, interopAddress, // interop address token.ToString(), amount ) ); } } } if (tx.script != null && tx.script.Length > 0) // NEP5 transfers { var script = NeoDisassembler.Disassemble(tx.script, true); //logger.Debug("SCRIPT ===================="); //foreach (var entry in script.lines) //{ // logger.Debug($"{entry.name} : { entry.opcode }"); //} //logger.Debug("SCRIPT ===================="); if (script.lines.Count() < 7) { //logger.Debug("NO SCRIPT!!!!"); return(emptyTx); } var disasmEntry = script.lines.ElementAtOrDefault(6); //if ( disasmEntry == null ) //{ // logger.Debug("disasmEntry is null"); //} //if ( disasmEntry != null ) //{ // if ( disasmEntry.data == null) // logger.Debug("disasmEntry.data is 0"); //} if (disasmEntry.name != "APPCALL" || disasmEntry.data == null || disasmEntry.data.Length == 0) { //logger.Debug("NO APPCALL"); return(emptyTx); } else { var assetString = new UInt160(disasmEntry.data).ToString(); if (string.IsNullOrEmpty(assetString) || FindSymbolFromAsset(assetString) == null) { //logger.Debug("Ignore TX due to non swapable token."); return(emptyTx); } } int pos = 0; foreach (var entry in script.lines) { pos++; if (pos > 3) { // we are only interested in the first three elements break; } if (entry.data == null || entry.data.Length == 0) { logger.Debug("Ignore tx, invalid data field: " + tx); return(emptyTx); } if (pos == 1) { amount = PBigInteger.FromUnsignedArray(entry.data, true); } if (pos == 2 || pos == 3) { if (pos == 2) { if (entry.data == null || entry.data.Length == 0) { logger.Debug("Invalid op on pos 2, ignoring tx: " + tx); return(emptyTx); } var targetScriptHash = new UInt160(entry.data); //logger.Debug("neo targetAddress: " + targetScriptHash.ToAddress()); var targetAddress = NeoWallet.EncodeByteArray(entry.data); //logger.Debug("targetAddress : " + targetAddress); //logger.Debug("interopSwapAddress: " + interopSwapAddress); //logger.Debug("SwapAddress: " + swapAddress); if (swapAddresses.Contains(targetAddress)) { // found a swap, call getapplicationlog now to get transaction details and verify the tx was actually processed. ApplicationLog[] appLogs = null; try { appLogs = api.GetApplicationLog(tx.Hash); } catch (Exception e) { logger.Error("Getting application logs failed: " + e.Message); return(new InteropTransaction(Hash.Null, interopTransfers.ToArray())); } if (appLogs != null) { for (var i = 0; i < appLogs.Length; i++) { //logger.Debug("appLogs[i].contract" + appLogs[i].contract); var token = FindSymbolFromAsset(appLogs[i].contract); //logger.Debug("TOKEN::::::::::::::::::: " + token); //logger.Debug("amount: " + appLogs[i].amount + " " + token); var sadd = NeoWallet.EncodeByteArray(appLogs[i].sourceAddress.ToArray()); var tadd = NeoWallet.EncodeByteArray(appLogs[i].targetAddress.ToArray()); interopTransfers.Add ( new InteropTransfer ( "neo", // todo Pay.Chains.NeoWallet.NeoPlatform //NeoWallet.EncodeByteArray(appLogs[i].sourceAddress.ToArray()), sourceAddress, DomainSettings.PlatformName, targetAddress, interopAddress, // interop address token, appLogs[i].amount ) ); } } else { logger.Warning("Neo swap is found but application log is not available for tx " + tx.Hash); } } } else { //TODO reverse swap sourceScriptHash = new UInt160(entry.data).ToArray(); sourceAddress = NeoWallet.EncodeByteArray(sourceScriptHash.ToArray()); } } } } var total = interopTransfers.Count(); if (total > 0) { logger.Message($"Found {total} swaps in neo tx {tx.Hash}"); } else { logger.Debug($"No swaps in neo tx {tx.Hash}"); } return((interopTransfers.Count() > 0) ? new InteropTransaction(Hash.Parse(tx.Hash.ToString()), interopTransfers.ToArray()) : new InteropTransaction(Hash.Null, interopTransfers.ToArray())); }
public async Task <string> TransferTokens(bool isFungible, PhantasmaKeys keyPair, string addressTo, string chainName, string symbol, string amountId, bool isName, MultisigSettings settings = new MultisigSettings()) { try { int decimals = PhantasmaTokens.SingleOrDefault(t => t.Symbol == symbol).Decimals; byte[] script; if (isFungible) { var bigIntAmount = UnitConversion.ToBigInteger(decimal.Parse(amountId), decimals); if (NeoWallet.IsValidAddress(addressTo)) { var addressNeo = NeoWallet.EncodeAddress(addressTo); Log.Information("Transfer to " + addressNeo); script = ScriptUtils.BeginScript() .AllowGas(keyPair.Address, Address.Null, MinimumFee, 800) .TransferTokens(symbol, keyPair.Address, addressNeo, bigIntAmount) .SpendGas(keyPair.Address) .EndScript(); } else { if (isName) { Log.Information("Transfer to " + addressTo); script = ScriptUtils.BeginScript() .AllowGas(keyPair.Address, Address.Null, MinimumFee, 800) .TransferTokens(symbol, keyPair.Address, addressTo, bigIntAmount) .SpendGas(keyPair.Address) .EndScript(); } else { var destinationAddress = Address.FromText(addressTo); Log.Information("Transfer to " + destinationAddress.Text); script = ScriptUtils.BeginScript() .AllowGas(keyPair.Address, Address.Null, MinimumFee, 800) .TransferTokens(symbol, keyPair.Address, destinationAddress, bigIntAmount) .SpendGas(keyPair.Address) .EndScript(); } } } else { var bigIntAmount = BigInteger.Parse(amountId); if (isName) { Log.Information("Transfer to " + addressTo); script = ScriptUtils.BeginScript() .AllowGas(keyPair.Address, Address.Null, MinimumFee, 800) .TransferNFT(symbol, keyPair.Address, addressTo, bigIntAmount) .SpendGas(keyPair.Address) .EndScript(); } else { var destinationAddress = Address.FromText(addressTo); Log.Information("Transfer to " + destinationAddress.Text); script = ScriptUtils.BeginScript() .AllowGas(keyPair.Address, Address.Null, MinimumFee, 800) .TransferNFT(symbol, keyPair.Address, destinationAddress, bigIntAmount) .SpendGas(keyPair.Address) .EndScript(); } } var nexusName = WalletConfig.Network; var tx = new Phantasma.Blockchain.Transaction(nexusName, chainName, script, DateTime.UtcNow + TimeSpan.FromMinutes(30), "PHT-0-8-7"); tx.Sign(keyPair); // from here on we need PhantasmaRelay to proceed with a multisig TX // //if (settings.addressCount != null) //{ // //} var txResult = await _phantasmaRpcService.SendRawTx.SendRequestAsync(tx.ToByteArray(true).Encode()); Log.Information("txResult send: " + txResult); return(txResult); } catch (RpcResponseException rpcEx) { Log.Information($"RPC Exception occurred: {rpcEx.RpcError.Message}"); return(""); } catch (Exception ex) { Log.Information($"Exception occurred: {ex.Message}"); return(""); } }
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); } }
/// <summary> /// Sign a message /// </summary> /// <param name="toSign">Message to sign</param> /// <param name="wallet">Wallet for signature</param> /// <returns>String of signature</returns> public string SignTransaction(byte[] toSign, NeoWallet wallet) { return(GenerateSignature(toSign, wallet)); }
/// <summary> /// Sign a message /// </summary> /// <param name="message">Message to sign</param> /// <param name="wallet">Wallet for signature</param> /// <returns>String of signature</returns> public string SignMessage(string message, NeoWallet wallet) { var serializedTransaction = PrepAndSerializeMessage(message); return(GenerateSignature(serializedTransaction, wallet)); }
public void NeoWalletScriptHash_Test() { var neoWallet = new NeoWallet(_scriptHash); Assert.True(_address == neoWallet.address); }