Skip to content

Commit

Permalink
- added multiple address generate, balance and send support
Browse files Browse the repository at this point in the history
- added "generate" and "sendfrom" commands
- updated "balance" command to show balances for all addresses and total balance
- removed addresses command
- removed deprecated ProtocolMessageCode.balance
  • Loading branch information
firestorm40 committed May 25, 2023
1 parent b55ebc8 commit d99ccff
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 97 deletions.
100 changes: 82 additions & 18 deletions IxianLiteWallet/Commands/Commands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,6 @@ public void handleCommand(string line)
handleAddress();
break;

case "addresses":
handleAddresses();
break;

case "backup":
handleBackup();
break;
Expand All @@ -73,10 +69,18 @@ public void handleCommand(string line)
handleChangePass();
break;

case "generate":
handleGenerate();
break;

case "send":
handleSend(line);
break;

case "sendfrom":
handleSendFrom(line);
break;

case "verify":
handleVerify(line);
break;
Expand All @@ -95,35 +99,55 @@ void handleHelp()
Console.WriteLine("\tstatus\t\t\t-shows the number of connected DLT nodes");
Console.WriteLine("\tnodes\t\t\t-shows the connected DLT nodes and their versions");
Console.WriteLine("\treconnect\t\t-reconnects to the Ixian DLT network");
Console.WriteLine("\tbalance\t\t\t-shows this wallet balance");
Console.WriteLine("\taddress\t\t\t-shows this wallet's primary address");
Console.WriteLine("\taddresses\t\t-shows all addresses for this wallet");
Console.WriteLine("\tgenerate\t\t-generates a new address for this wallet");
Console.WriteLine("\taddress\t\t\t-shows all addresses for this wallet");
Console.WriteLine("\tbalance\t\t\t-shows all address balances for this wallet");
Console.WriteLine("\tbackup\t\t\t-backup this wallet as an IXIHEX text");
Console.WriteLine("\tchangepass\t\t-changes this wallet's password");
//Console.WriteLine("\tverify [txid]\t\t-verifies the specified transaction txid");
Console.WriteLine("\tsend [address] [amount]\t-sends IxiCash to the specified address");
// generate new address, view all address balances
Console.WriteLine("\tsendfrom [fromaddress] [toaddress] [amount] -sends IxiCash from a specific address to the specified address");
// change password
Console.WriteLine("");
}

void handleBalance()
{
Node.getBalance();
string verified = "";
if (Node.balance.verified)
List<Address> address_list = IxianHandler.getWalletStorage().getMyAddresses();

IxiNumber total_balance = 0;
foreach (Address addr in address_list)
{
//verified = " (verified)"; // not yet
Node.getBalance(addr.addressWithChecksum);

IxiNumber address_balance = 0;
string verified = "";

foreach (Balance balance in Node.balances)
{
if (balance.address != null && balance.address.addressWithChecksum.SequenceEqual(addr.addressWithChecksum))
{
address_balance = balance.balance;

/*if (balance.verified)
{
verified = " (verified)"; // not yet
}*/
}
}

Console.WriteLine("{0} : {1} IXI{2}", addr.ToString(), address_balance, verified);
total_balance += address_balance;
}
Console.WriteLine("Balance: {0} IXI{1}\n", Node.balance.balance, verified);
}
Console.WriteLine("--------------");

void handleAddress()
{
Console.WriteLine("Primary address: {0}\n", IxianHandler.getWalletStorage().getPrimaryAddress().ToString());

Console.WriteLine("Total Balance: {0} IXI\n", total_balance);

Console.WriteLine("");
}

void handleAddresses()
void handleAddress()
{
List<Address> address_list = IxianHandler.getWalletStorage().getMyAddresses();

Expand Down Expand Up @@ -184,6 +208,11 @@ void handleChangePass()
Console.WriteLine("Wallet password changed.");
}

void handleGenerate()
{
Node.generateNewAddress();
}

void handleSend(string line)
{
string[] split = line.Split(new string[] { " " }, StringSplitOptions.None);
Expand All @@ -210,6 +239,41 @@ void handleSend(string line)
Node.sendTransaction(new Address(_address), amount);
}

void handleSendFrom(string line)
{
string[] split = line.Split(new string[] { " " }, StringSplitOptions.None);
if (split.Count() < 4)
{
Console.WriteLine("Incorrect parameters for sendfrom. Should be fromAddress, address and amount.\n");
return;
}
string fromAddress = split[1];
// Validate the from address first
byte[] _fromAddress = Base58Check.Base58CheckEncoding.DecodePlain(fromAddress);
if (Address.validateChecksum(_fromAddress) == false)
{
Console.WriteLine("Invalid fromAddress checksum!. Please make sure you typed the address correctly.\n");
return;
}

string address = split[2];
// Validate the to address first
byte[] _address = Base58Check.Base58CheckEncoding.DecodePlain(address);
if (Address.validateChecksum(_address) == false)
{
Console.WriteLine("Invalid address checksum!. Please make sure you typed the address correctly.\n");
return;
}
// Make sure the amount is positive
IxiNumber amount = new IxiNumber(split[3]);
if (amount < (long)0)
{
Console.WriteLine("Please type a positive amount.\n");
return;
}
Node.sendTransactionFrom(new Address(_fromAddress), new Address(_address), amount);
}

void handleVerify(string line)
{
string[] split = line.Split(new string[] { " " }, StringSplitOptions.None);
Expand Down
114 changes: 86 additions & 28 deletions IxianLiteWallet/Meta/Node.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,19 @@ class Balance
public ulong blockHeight = 0;
public byte[] blockChecksum = null;
public bool verified = false;

public Balance(Address address, IxiNumber balance)
{
this.address = address;
this.balance = balance;
}
}

class Node : IxianNode
{
public static bool running = false;

public static Balance balance = new Balance(); // Stores the last known balance for this node
public static List<Balance> balances = new List<Balance>(); // Stores the last known balances for this node

public static TransactionInclusion tiv = null;

Expand Down Expand Up @@ -145,6 +151,13 @@ private bool initWallet()

IxianHandler.addWallet(walletStorage);

// Prepare the balances list
List<Address> address_list = IxianHandler.getWalletStorage().getMyAddresses();
foreach (Address addr in address_list)
{
balances.Add(new Balance(addr, 0));
}

return true;
}

Expand Down Expand Up @@ -184,55 +197,96 @@ public void start()
}
}

static public void getBalance()
static public void getBalance(byte[] address)
{
ProtocolMessage.setWaitFor(ProtocolMessageCode.balance2);
ProtocolMessage.setWaitFor(ProtocolMessageCode.balance2, address);

// Return the balance for the matching address
using (MemoryStream mw = new MemoryStream())
{
using (BinaryWriter writer = new BinaryWriter(mw))
{
writer.WriteIxiVarInt(IxianHandler.getWalletStorage().getPrimaryAddress().addressWithChecksum.Length);
writer.Write(IxianHandler.getWalletStorage().getPrimaryAddress().addressWithChecksum);
writer.WriteIxiVarInt(address.Length);
writer.Write(address);
NetworkClientManager.broadcastData(new char[] { 'M', 'H' }, ProtocolMessageCode.getBalance2, mw.ToArray(), null);
}
}
ProtocolMessage.wait(30);
}

static public void generateNewAddress()
{
Address base_address = IxianHandler.getWalletStorage().getPrimaryAddress();
Address new_address = IxianHandler.getWalletStorage().generateNewAddress(base_address, null);
if (new_address != null)
{
balances.Add(new Balance(new_address, 0));
Console.WriteLine("New address generated: {0}", new_address.ToString());
}
else
{
Console.WriteLine("Error occurred while generating a new address");
}
}

static public void sendTransaction(Address address, IxiNumber amount)
{

getBalance();
// TODO add support for sending funds from multiple addreses automatically based on remaining balance
Balance address_balance = balances.First();
var from = address_balance.address;
sendTransactionFrom(from, address, amount);
}

static public void sendTransactionFrom(Address fromAddress, Address address, IxiNumber amount)
{
getBalance(fromAddress.addressWithChecksum);

IxiNumber fee = ConsensusConfig.forceTransactionPrice;
SortedDictionary<Address, ToEntry> to_list = new(new AddressComparer());
Balance address_balance = balances.FirstOrDefault(addr => addr.address.addressWithChecksum.SequenceEqual(fromAddress.addressWithChecksum));
Address pubKey = new(IxianHandler.getWalletStorage().getPrimaryPublicKey());

if (balance.balance < amount)
if (!IxianHandler.getWalletStorage().isMyAddress(fromAddress))
{
Console.WriteLine("Insufficient funds.\n");
Console.WriteLine("From address is not my address.\n");
return;
}

SortedDictionary<Address, ToEntry> to_list = new SortedDictionary<Address, ToEntry>(new AddressComparer());
SortedDictionary<byte[], IxiNumber> from_list = new(new ByteArrayComparer())
{
{ IxianHandler.getWalletStorage().getAddress(fromAddress).nonce, amount }
};

to_list.AddOrReplace(address, new ToEntry(Transaction.getExpectedVersion(IxianHandler.getLastBlockVersion()), amount));

IxiNumber fee = ConsensusConfig.forceTransactionPrice;
var from = IxianHandler.getWalletStorage().getPrimaryAddress();
Address pubKey = new Address(IxianHandler.getWalletStorage().getPrimaryPublicKey());
var toEntry = new ToEntry(Transaction.getExpectedVersion(IxianHandler.getLastBlockVersion()), amount);
to_list.AddOrReplace(address, toEntry);
Transaction transaction = new Transaction((int)Transaction.Type.Normal, fee, to_list, from, pubKey, IxianHandler.getHighestKnownNetworkBlockHeight());
if (transaction.amount + transaction.fee > balance.balance)
// Prepare transaction to calculate fee
Transaction transaction = new((int)Transaction.Type.Normal, fee, to_list, from_list, pubKey, IxianHandler.getHighestKnownNetworkBlockHeight());

byte[] first_address = from_list.Keys.First();
from_list[first_address] = from_list[first_address] + transaction.fee;
IxiNumber wal_bal = IxianHandler.getWalletBalance(new Address(transaction.pubKey.addressNoChecksum, first_address));
if (from_list[first_address] > wal_bal)
{
Console.WriteLine("Insufficient funds.\n");
IxiNumber maxAmount = wal_bal - transaction.fee;

if (maxAmount < 0)
maxAmount = 0;

Console.WriteLine("Insufficient funds to cover amount and transaction fee.\nMaximum amount you can send is {0} IXI.\n", maxAmount);
return;
}
// Prepare transaction with updated "from" amount to cover fee
transaction = new((int)Transaction.Type.Normal, fee, to_list, from_list, pubKey, IxianHandler.getHighestKnownNetworkBlockHeight());

// Send the transaction
if (IxianHandler.addTransaction(transaction, true))
{
Console.WriteLine("Sending transaction, txid: {0}\n", transaction.getTxIdString());
}else
}
else
{
Console.WriteLine("Could not send transaction\n");
}

}

static public void setNetworkBlock(ulong block_height, byte[] block_checksum, int block_version)
Expand All @@ -255,10 +309,14 @@ public override void receivedTransactionInclusionVerificationResponse(byte[] txi

public override void receivedBlockHeader(Block block_header, bool verified)
{
if(balance.blockChecksum != null && balance.blockChecksum.SequenceEqual(block_header.blockChecksum))
foreach (Balance balance in balances)
{
balance.verified = true;
if (balance.blockChecksum != null && balance.blockChecksum.SequenceEqual(block_header.blockChecksum))
{
balance.verified = true;
}
}

if(block_header.blockNum >= networkBlockHeight)
{
IxianHandler.status = NodeStatus.ready;
Expand Down Expand Up @@ -312,20 +370,20 @@ public override Block getLastBlock()

public override Wallet getWallet(Address id)
{
// TODO Properly implement this for multiple addresses
if (balance.address != null && id.addressNoChecksum.SequenceEqual(balance.address.addressNoChecksum))
foreach (Balance balance in balances)
{
return new Wallet(id, balance.balance);
if (id.addressNoChecksum.SequenceEqual(balance.address.addressNoChecksum))
return new Wallet(id, balance.balance);
}
return new Wallet(id, 0);
}

public override IxiNumber getWalletBalance(Address id)
{
// TODO Properly implement this for multiple addresses
if (balance.address != null && id.addressNoChecksum.SequenceEqual(balance.address.addressNoChecksum))
foreach (Balance balance in balances)
{
return balance.balance;
if (id.addressNoChecksum.SequenceEqual(balance.address.addressNoChecksum))
return balance.balance;
}
return 0;
}
Expand Down

0 comments on commit d99ccff

Please sign in to comment.