package qora.assets; import java.nio.charset.StandardCharsets; import java.util.Arrays; import com.google.common.primitives.Bytes; import com.google.common.primitives.Ints; import com.google.common.primitives.Longs; import database.DBSet; import qora.account.Account; import qora.crypto.Base58; public class Asset { private static final int OWNER_LENGTH = 25; private static final int NAME_SIZE_LENGTH = 4; private static final int DESCRIPTION_SIZE_LENGTH = 4; private static final int QUANTITY_LENGTH = 8; private static final int DIVISIBLE_LENGTH = 1; private static final int REFERENCE_LENGTH = 64; private Account owner; private String name; private String description; private long quantity; private boolean divisible; private byte[] reference; public Asset(Account owner, String name, String description, long quantity, boolean divisible, byte[] reference) { this.owner = owner; this.name = name; this.description = description; this.quantity = quantity; this.divisible = divisible; this.reference = reference; } //GETTERS/SETTERS public Account getOwner() { return this.owner; } public String getName() { return this.name; } public String getDescription() { return this.description; } public Long getQuantity() { return this.quantity; } public boolean isDivisible() { return this.divisible; } public byte[] getReference() { return this.reference; } public long getKey() { return DBSet.getInstance().getIssueAssetMap().get(this.reference); } public boolean isConfirmed() { return DBSet.getInstance().getIssueAssetMap().contains(this.reference); } //PARSE public static Asset parse(byte[] data) throws Exception { int position = 0; //READ OWNER byte[] ownerBytes = Arrays.copyOfRange(data, position, position + OWNER_LENGTH); Account owner = new Account(Base58.encode(ownerBytes)); position += OWNER_LENGTH; //READ NAME byte[] nameLengthBytes = Arrays.copyOfRange(data, position, position + NAME_SIZE_LENGTH); int nameLength = Ints.fromByteArray(nameLengthBytes); position += NAME_SIZE_LENGTH; if(nameLength < 1 || nameLength > 400) { throw new Exception("Invalid name length"); } byte[] nameBytes = Arrays.copyOfRange(data, position, position + nameLength); String name = new String(nameBytes, StandardCharsets.UTF_8); position += nameLength; //READ DESCRIPTION byte[] descriptionLengthBytes = Arrays.copyOfRange(data, position, position + DESCRIPTION_SIZE_LENGTH); int descriptionLength = Ints.fromByteArray(descriptionLengthBytes); position += DESCRIPTION_SIZE_LENGTH; if(descriptionLength < 1 || descriptionLength > 4000) { throw new Exception("Invalid description length"); } byte[] descriptionBytes = Arrays.copyOfRange(data, position, position + descriptionLength); String description = new String(descriptionBytes, StandardCharsets.UTF_8); position += descriptionLength; //READ QUANTITY byte[] quantityBytes = Arrays.copyOfRange(data, position, position + QUANTITY_LENGTH); long quantity = Longs.fromByteArray(quantityBytes); position += QUANTITY_LENGTH; //READ DIVISABLE byte[] divisibleBytes = Arrays.copyOfRange(data, position, position + DIVISIBLE_LENGTH); boolean divisable = divisibleBytes[0] == 1; position += DIVISIBLE_LENGTH; //READ REFERENCE byte[] reference = Arrays.copyOfRange(data, position, position + REFERENCE_LENGTH); //RETURN return new Asset(owner, name, description, quantity, divisable, reference); } /*@SuppressWarnings("unchecked") public JSONObject toJson() { //GET BASE JSONObject name = new JSONObject(); //ADD NAME/VALUE/OWNER name.put("name", this.getName()); name.put("value", this.getValue()); name.put("owner", this.getOwner().getAddress()); return name; }*/ public byte[] toBytes(boolean includeReference) { byte[] data = new byte[0]; //WRITE OWNER try { data = Bytes.concat(data , Base58.decode(this.owner.getAddress())); } catch(Exception e) { //DECODE EXCEPTION } //WRITE NAME SIZE byte[] nameBytes = this.name.getBytes(StandardCharsets.UTF_8); int nameLength = nameBytes.length; byte[] nameLengthBytes = Ints.toByteArray(nameLength); data = Bytes.concat(data, nameLengthBytes); //WRITE NAME data = Bytes.concat(data, nameBytes); //WRITE DESCRIPTION SIZE byte[] descriptionBytes = this.description.getBytes(StandardCharsets.UTF_8); int descriptionLength = descriptionBytes.length; byte[] descriptionLengthBytes = Ints.toByteArray(descriptionLength); data = Bytes.concat(data, descriptionLengthBytes); //WRITE DESCRIPTION data = Bytes.concat(data, descriptionBytes); //WRITE QUANTITY byte[] quantityBytes = Longs.toByteArray(this.quantity); data = Bytes.concat(data, quantityBytes); //WRITE DIVISIBLE byte[] divisibleBytes = new byte[1]; divisibleBytes[0] = (byte) (this.divisible == true ? 1 : 0); data = Bytes.concat(data, divisibleBytes); if(includeReference) { //WRITE REFERENCE data = Bytes.concat(data, this.reference); } else { //WRITE EMPTY REFERENCE data = Bytes.concat(data, new byte[64]); } return data; } public int getDataLength() { return OWNER_LENGTH + NAME_SIZE_LENGTH + this.name.getBytes(StandardCharsets.UTF_8).length + DESCRIPTION_SIZE_LENGTH + this.description.getBytes(StandardCharsets.UTF_8).length + QUANTITY_LENGTH + DIVISIBLE_LENGTH + REFERENCE_LENGTH; } //OTHER public String toString() { if(this.getKey() == 0) { return "Qora"; } else { return "(" + this.getKey() + ") " + this.getName(); } } }