Tidy up Assets by removing 'owner' from ISSUE_ASSET.

Owner now derived from issuer's public key.
Maximum asset name length reduced to 40 characters.

Repository table changes.

"owner" removed from test blockchain configs and "issuerPublicKey" used instead
where applicable.

Some getters in the form of "getIs___()" renamed to simply "is____()".
This commit is contained in:
catbref 2020-05-15 16:22:13 +01:00
parent f6ed3388a4
commit 38a2af8cd5
21 changed files with 85 additions and 112 deletions

View File

@ -1,5 +1,6 @@
package org.qortal.asset;
import org.qortal.crypto.Crypto;
import org.qortal.data.asset.AssetData;
import org.qortal.data.transaction.IssueAssetTransactionData;
import org.qortal.data.transaction.TransactionData;
@ -22,7 +23,7 @@ public class Asset {
// Other useful constants
public static final int MAX_NAME_SIZE = 400;
public static final int MAX_NAME_SIZE = 40;
public static final int MAX_DESCRIPTION_SIZE = 4000;
public static final int MAX_DATA_SIZE = 400000;
@ -42,11 +43,13 @@ public class Asset {
public Asset(Repository repository, IssueAssetTransactionData issueAssetTransactionData) {
this.repository = repository;
String ownerAddress = Crypto.toAddress(issueAssetTransactionData.getCreatorPublicKey());
// NOTE: transaction's reference is used to look up newly assigned assetID on creation!
this.assetData = new AssetData(issueAssetTransactionData.getOwner(), issueAssetTransactionData.getAssetName(),
this.assetData = new AssetData(ownerAddress, issueAssetTransactionData.getAssetName(),
issueAssetTransactionData.getDescription(), issueAssetTransactionData.getQuantity(),
issueAssetTransactionData.getIsDivisible(), issueAssetTransactionData.getData(),
issueAssetTransactionData.getIsUnspendable(),
issueAssetTransactionData.isDivisible(), issueAssetTransactionData.getData(),
issueAssetTransactionData.isUnspendable(),
issueAssetTransactionData.getTxGroupId(), issueAssetTransactionData.getSignature());
}
@ -118,10 +121,11 @@ public class Asset {
throw new IllegalStateException("Missing referenced transaction when orphaning UPDATE_ASSET");
switch (previousTransactionData.getType()) {
case ISSUE_ASSET:
case ISSUE_ASSET: {
IssueAssetTransactionData previousIssueAssetTransactionData = (IssueAssetTransactionData) previousTransactionData;
this.assetData.setOwner(previousIssueAssetTransactionData.getOwner());
String ownerAddress = Crypto.toAddress(previousIssueAssetTransactionData.getCreatorPublicKey());
this.assetData.setOwner(ownerAddress);
if (needDescription) {
this.assetData.setDescription(previousIssueAssetTransactionData.getDescription());
@ -133,8 +137,9 @@ public class Asset {
needData = false;
}
break;
}
case UPDATE_ASSET:
case UPDATE_ASSET: {
UpdateAssetTransactionData previousUpdateAssetTransactionData = (UpdateAssetTransactionData) previousTransactionData;
this.assetData.setOwner(previousUpdateAssetTransactionData.getNewOwner());
@ -152,7 +157,9 @@ public class Asset {
// Get signature for previous transaction in chain, just in case we need it
if (needDescription || needData)
previousTransactionSignature = previousUpdateAssetTransactionData.getOrphanReference();
break;
}
default:
throw new IllegalStateException("Invalid referenced transaction when orphaning UPDATE_ASSET");

View File

@ -335,7 +335,7 @@ public class Order {
continue;
// Calculate amount granularity, based on price and both assets' divisibility, so that return-amount traded is a valid value (integer or to 8 d.p.)
long granularity = calculateAmountGranularity(matchingAssetData.getIsDivisible(), returnAssetData.getIsDivisible(), theirOrderData.getPrice());
long granularity = calculateAmountGranularity(matchingAssetData.isDivisible(), returnAssetData.isDivisible(), theirOrderData.getPrice());
LOGGER.trace(() -> String.format("granularity (amount granularity): %s %s", prettyAmount(granularity), matchingAssetData.getName()));
// Reduce matched amount (if need be) to fit granularity
@ -395,7 +395,7 @@ public class Order {
* @throws DataException if divisibility check fails
*/
private void checkDivisibility(AssetData assetData, long amount, OrderData orderData) throws DataException {
if (assetData.getIsDivisible() || amount % Amounts.MULTIPLIER == 0)
if (assetData.isDivisible() || amount % Amounts.MULTIPLIER == 0)
// Asset is divisible or amount has no fractional part
return;

View File

@ -84,7 +84,7 @@ public class AssetData {
return this.quantity;
}
public boolean getIsDivisible() {
public boolean isDivisible() {
return this.isDivisible;
}
@ -96,7 +96,7 @@ public class AssetData {
this.data = data;
}
public boolean getIsUnspendable() {
public boolean isUnspendable() {
return this.isUnspendable;
}

View File

@ -29,9 +29,6 @@ public class IssueAssetTransactionData extends TransactionData {
@Schema(description = "asset issuer's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP")
private byte[] issuerPublicKey;
@Schema(description = "asset owner's address", example = "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v")
private String owner;
@Schema(description = "asset name", example = "GOLD")
private String assetName;
@ -72,12 +69,11 @@ public class IssueAssetTransactionData extends TransactionData {
/** From repository */
public IssueAssetTransactionData(BaseTransactionData baseTransactionData,
Long assetId, String owner, String assetName, String description, long quantity, boolean isDivisible, String data, boolean isUnspendable) {
Long assetId, String assetName, String description, long quantity, boolean isDivisible, String data, boolean isUnspendable) {
super(TransactionType.ISSUE_ASSET, baseTransactionData);
this.assetId = assetId;
this.issuerPublicKey = baseTransactionData.creatorPublicKey;
this.owner = owner;
this.assetName = assetName;
this.description = description;
this.quantity = quantity;
@ -87,9 +83,9 @@ public class IssueAssetTransactionData extends TransactionData {
}
/** From network/API */
public IssueAssetTransactionData(BaseTransactionData baseTransactionData, String owner, String assetName, String description,
public IssueAssetTransactionData(BaseTransactionData baseTransactionData, String assetName, String description,
long quantity, boolean isDivisible, String data, boolean isUnspendable) {
this(baseTransactionData, null, owner, assetName, description, quantity, isDivisible, data, isUnspendable);
this(baseTransactionData, null, assetName, description, quantity, isDivisible, data, isUnspendable);
}
// Getters/Setters
@ -106,14 +102,6 @@ public class IssueAssetTransactionData extends TransactionData {
return this.issuerPublicKey;
}
public String getOwner() {
return this.owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public String getAssetName() {
return this.assetName;
}
@ -126,7 +114,7 @@ public class IssueAssetTransactionData extends TransactionData {
return this.quantity;
}
public boolean getIsDivisible() {
public boolean isDivisible() {
return this.isDivisible;
}
@ -134,7 +122,7 @@ public class IssueAssetTransactionData extends TransactionData {
return this.data;
}
public boolean getIsUnspendable() {
public boolean isUnspendable() {
return this.isUnspendable;
}

View File

@ -86,7 +86,7 @@ public class Payment {
return ValidationResult.ASSET_DOES_NOT_EXIST;
// Do not allow non-owner asset holders to use asset
if (assetData.getIsUnspendable() && !assetData.getOwner().equals(sender.getAddress()))
if (assetData.isUnspendable() && !assetData.getOwner().equals(sender.getAddress()))
return ValidationResult.ASSET_NOT_SPENDABLE;
// If we're sending to an AT then assetId must match AT's assetId
@ -94,7 +94,7 @@ public class Payment {
return ValidationResult.ASSET_DOES_NOT_MATCH_AT;
// Check asset amount is integer if asset is not divisible
if (!assetData.getIsDivisible() && paymentData.getAmount() % Amounts.MULTIPLIER != 0)
if (!assetData.isDivisible() && paymentData.getAmount() % Amounts.MULTIPLIER != 0)
return ValidationResult.INVALID_AMOUNT;
// Set or add amount into amounts-by-asset map

View File

@ -159,8 +159,8 @@ public class HSQLDBAssetRepository implements AssetRepository {
saveHelper.bind("asset_id", assetData.getAssetId()).bind("owner", assetData.getOwner())
.bind("asset_name", assetData.getName()).bind("description", assetData.getDescription())
.bind("quantity", assetData.getQuantity()).bind("is_divisible", assetData.getIsDivisible())
.bind("data", assetData.getData()).bind("is_unspendable", assetData.getIsUnspendable())
.bind("quantity", assetData.getQuantity()).bind("is_divisible", assetData.isDivisible())
.bind("data", assetData.getData()).bind("is_unspendable", assetData.isUnspendable())
.bind("creation_group_id", assetData.getCreationGroupId()).bind("reference", assetData.getReference());
try {

View File

@ -380,8 +380,7 @@ public class HSQLDBDatabaseUpdates {
stmt.execute("CREATE INDEX AssetTradeSellOrderIndex on AssetTrades (target_order_id, traded_when)");
// Issue Asset Transactions
stmt.execute("CREATE TABLE IssueAssetTransactions (signature Signature, issuer QortalPublicKey NOT NULL, owner QortalAddress NOT NULL, "
+ "asset_name AssetName NOT NULL, "
stmt.execute("CREATE TABLE IssueAssetTransactions (signature Signature, issuer QortalPublicKey NOT NULL, asset_name AssetName NOT NULL, "
+ "description GenericDescription NOT NULL, quantity BIGINT NOT NULL, is_divisible BOOLEAN NOT NULL, asset_id AssetID, "
+ "is_unspendable BOOLEAN NOT NULL, data AssetData NOT NULL DEFAULT '', " + TRANSACTION_KEYS + ")");

View File

@ -17,26 +17,25 @@ public class HSQLDBIssueAssetTransactionRepository extends HSQLDBTransactionRepo
}
TransactionData fromBase(BaseTransactionData baseTransactionData) throws DataException {
String sql = "SELECT owner, asset_name, description, quantity, is_divisible, data, is_unspendable, asset_id FROM IssueAssetTransactions WHERE signature = ?";
String sql = "SELECT asset_name, description, quantity, is_divisible, data, is_unspendable, asset_id FROM IssueAssetTransactions WHERE signature = ?";
try (ResultSet resultSet = this.repository.checkedExecute(sql, baseTransactionData.getSignature())) {
if (resultSet == null)
return null;
String owner = resultSet.getString(1);
String assetName = resultSet.getString(2);
String description = resultSet.getString(3);
long quantity = resultSet.getLong(4);
boolean isDivisible = resultSet.getBoolean(5);
String data = resultSet.getString(6);
boolean isUnspendable = resultSet.getBoolean(7);
String assetName = resultSet.getString(1);
String description = resultSet.getString(2);
long quantity = resultSet.getLong(3);
boolean isDivisible = resultSet.getBoolean(4);
String data = resultSet.getString(5);
boolean isUnspendable = resultSet.getBoolean(6);
// Special null-checking for asset ID
Long assetId = resultSet.getLong(8);
Long assetId = resultSet.getLong(7);
if (assetId == 0 && resultSet.wasNull())
assetId = null;
return new IssueAssetTransactionData(baseTransactionData, assetId, owner, assetName, description, quantity, isDivisible,
return new IssueAssetTransactionData(baseTransactionData, assetId, assetName, description, quantity, isDivisible,
data, isUnspendable);
} catch (SQLException e) {
throw new DataException("Unable to fetch issue asset transaction from repository", e);
@ -50,10 +49,10 @@ public class HSQLDBIssueAssetTransactionRepository extends HSQLDBTransactionRepo
HSQLDBSaver saveHelper = new HSQLDBSaver("IssueAssetTransactions");
saveHelper.bind("signature", issueAssetTransactionData.getSignature()).bind("issuer", issueAssetTransactionData.getIssuerPublicKey())
.bind("owner", issueAssetTransactionData.getOwner()).bind("asset_name", issueAssetTransactionData.getAssetName())
.bind("asset_name", issueAssetTransactionData.getAssetName())
.bind("description", issueAssetTransactionData.getDescription()).bind("quantity", issueAssetTransactionData.getQuantity())
.bind("is_divisible", issueAssetTransactionData.getIsDivisible()).bind("data", issueAssetTransactionData.getData())
.bind("is_unspendable", issueAssetTransactionData.getIsUnspendable()).bind("asset_id", issueAssetTransactionData.getAssetId());
.bind("is_divisible", issueAssetTransactionData.isDivisible()).bind("data", issueAssetTransactionData.getData())
.bind("is_unspendable", issueAssetTransactionData.isUnspendable()).bind("asset_id", issueAssetTransactionData.getAssetId());
try {
saveHelper.execute(this.repository);

View File

@ -114,7 +114,7 @@ public class AtTransaction extends Transaction {
return ValidationResult.ASSET_DOES_NOT_EXIST;
// Check asset amount is integer if asset is not divisible
if (!assetData.getIsDivisible() && amount % Amounts.MULTIPLIER != 0)
if (!assetData.isDivisible() && amount % Amounts.MULTIPLIER != 0)
return ValidationResult.INVALID_AMOUNT;
Account sender = getATAccount();

View File

@ -76,7 +76,7 @@ public class CreateAssetOrderTransaction extends Transaction {
return ValidationResult.ASSET_DOES_NOT_EXIST;
// Unspendable assets are not tradable
if (haveAssetData.getIsUnspendable() || wantAssetData.getIsUnspendable())
if (haveAssetData.isUnspendable() || wantAssetData.isUnspendable())
return ValidationResult.ASSET_NOT_SPENDABLE;
Account creator = getCreator();
@ -109,11 +109,11 @@ public class CreateAssetOrderTransaction extends Transaction {
}
// Check amount is integer if amount's asset is not divisible
if (!haveAssetData.getIsDivisible() && committedCost.mod(Amounts.MULTIPLIER_BI).signum() != 0)
if (!haveAssetData.isDivisible() && committedCost.mod(Amounts.MULTIPLIER_BI).signum() != 0)
return ValidationResult.INVALID_AMOUNT;
// Check total return from fulfilled order would be integer if return's asset is not divisible
if (!wantAssetData.getIsDivisible() && maxOtherAmount.mod(Amounts.MULTIPLIER_BI).signum() != 0)
if (!wantAssetData.isDivisible() && maxOtherAmount.mod(Amounts.MULTIPLIER_BI).signum() != 0)
return ValidationResult.INVALID_RETURN;
// Check order creator has enough asset balance AFTER removing fee, in case asset is QORT

View File

@ -113,11 +113,11 @@ public class DeployAtTransaction extends Transaction {
return ValidationResult.ASSET_DOES_NOT_EXIST;
// Unspendable assets are not valid
if (assetData.getIsUnspendable())
if (assetData.isUnspendable())
return ValidationResult.ASSET_NOT_SPENDABLE;
// Check asset amount is integer if asset is not divisible
if (!assetData.getIsDivisible() && this.deployATTransactionData.getAmount() % Amounts.MULTIPLIER != 0)
if (!assetData.isDivisible() && this.deployATTransactionData.getAmount() % Amounts.MULTIPLIER != 0)
return ValidationResult.INVALID_AMOUNT;
Account creator = this.getCreator();

View File

@ -5,7 +5,6 @@ import java.util.List;
import org.qortal.account.Account;
import org.qortal.asset.Asset;
import org.qortal.crypto.Crypto;
import org.qortal.data.transaction.IssueAssetTransactionData;
import org.qortal.data.transaction.TransactionData;
import org.qortal.repository.DataException;
@ -19,7 +18,6 @@ public class IssueAssetTransaction extends Transaction {
// Properties
private IssueAssetTransactionData issueAssetTransactionData;
private Account ownerAccount = null;
// Constructors
@ -33,7 +31,7 @@ public class IssueAssetTransaction extends Transaction {
@Override
public List<String> getRecipientAddresses() throws DataException {
return Collections.singletonList(this.issueAssetTransactionData.getOwner());
return Collections.emptyList();
}
// Navigation
@ -42,21 +40,10 @@ public class IssueAssetTransaction extends Transaction {
return this.getCreator();
}
public Account getOwner() {
if (this.ownerAccount == null)
this.ownerAccount = new Account(this.repository, this.issueAssetTransactionData.getOwner());
return this.ownerAccount;
}
// Processing
@Override
public ValidationResult isValid() throws DataException {
// Check owner address is valid
if (!Crypto.isValidAddress(this.issueAssetTransactionData.getOwner()))
return ValidationResult.INVALID_ADDRESS;
// Check name size bounds
int assetNameLength = Utf8.encodedLength(this.issueAssetTransactionData.getAssetName());
if (assetNameLength < 1 || assetNameLength > Asset.MAX_NAME_SIZE)
@ -78,7 +65,7 @@ public class IssueAssetTransaction extends Transaction {
return ValidationResult.INVALID_QUANTITY;
// Check quantity versus indivisibility
if (!this.issueAssetTransactionData.getIsDivisible() && this.issueAssetTransactionData.getQuantity() % Amounts.MULTIPLIER != 0)
if (!this.issueAssetTransactionData.isDivisible() && this.issueAssetTransactionData.getQuantity() % Amounts.MULTIPLIER != 0)
return ValidationResult.INVALID_QUANTITY;
Account issuer = getIssuer();
@ -105,9 +92,9 @@ public class IssueAssetTransaction extends Transaction {
Asset asset = new Asset(this.repository, this.issueAssetTransactionData);
asset.issue();
// Add asset to owner
Account owner = getOwner();
owner.setConfirmedBalance(asset.getAssetData().getAssetId(), this.issueAssetTransactionData.getQuantity());
// Add asset to issuer
Account issuer = this.getIssuer();
issuer.setConfirmedBalance(asset.getAssetData().getAssetId(), this.issueAssetTransactionData.getQuantity());
// Note newly assigned asset ID in our transaction record
this.issueAssetTransactionData.setAssetId(asset.getAssetData().getAssetId());
@ -118,9 +105,9 @@ public class IssueAssetTransaction extends Transaction {
@Override
public void orphan() throws DataException {
// Remove asset from owner
Account owner = getOwner();
owner.deleteBalance(this.issueAssetTransactionData.getAssetId());
// Remove asset from issuer
Account issuer = this.getIssuer();
issuer.deleteBalance(this.issueAssetTransactionData.getAssetId());
// Deissue asset
Asset asset = new Asset(this.repository, this.issueAssetTransactionData.getAssetId());

View File

@ -18,7 +18,6 @@ import com.google.common.primitives.Longs;
public class IssueAssetTransactionTransformer extends TransactionTransformer {
// Property lengths
private static final int OWNER_LENGTH = ADDRESS_LENGTH;
private static final int NAME_SIZE_LENGTH = INT_LENGTH;
private static final int DESCRIPTION_SIZE_LENGTH = INT_LENGTH;
private static final int QUANTITY_LENGTH = AMOUNT_LENGTH;
@ -26,7 +25,7 @@ public class IssueAssetTransactionTransformer extends TransactionTransformer {
private static final int DATA_SIZE_LENGTH = INT_LENGTH;
private static final int IS_UNSPENDABLE_LENGTH = BOOLEAN_LENGTH;
private static final int EXTRAS_LENGTH = OWNER_LENGTH + NAME_SIZE_LENGTH + DESCRIPTION_SIZE_LENGTH + QUANTITY_LENGTH
private static final int EXTRAS_LENGTH = NAME_SIZE_LENGTH + DESCRIPTION_SIZE_LENGTH + QUANTITY_LENGTH
+ IS_DIVISIBLE_LENGTH + DATA_SIZE_LENGTH + IS_UNSPENDABLE_LENGTH;
protected static final TransactionLayout layout;
@ -38,7 +37,6 @@ public class IssueAssetTransactionTransformer extends TransactionTransformer {
layout.add("transaction's groupID", TransformationType.INT);
layout.add("reference", TransformationType.SIGNATURE);
layout.add("asset issuer's public key", TransformationType.PUBLIC_KEY);
layout.add("asset owner", TransformationType.ADDRESS);
layout.add("asset name length", TransformationType.INT);
layout.add("asset name", TransformationType.STRING);
layout.add("asset description length", TransformationType.INT);
@ -62,8 +60,6 @@ public class IssueAssetTransactionTransformer extends TransactionTransformer {
byte[] issuerPublicKey = Serialization.deserializePublicKey(byteBuffer);
String owner = Serialization.deserializeAddress(byteBuffer);
String assetName = Serialization.deserializeSizedString(byteBuffer, Asset.MAX_NAME_SIZE);
String description = Serialization.deserializeSizedString(byteBuffer, Asset.MAX_DESCRIPTION_SIZE);
@ -83,7 +79,7 @@ public class IssueAssetTransactionTransformer extends TransactionTransformer {
BaseTransactionData baseTransactionData = new BaseTransactionData(timestamp, txGroupId, reference, issuerPublicKey, fee, signature);
return new IssueAssetTransactionData(baseTransactionData, owner, assetName, description, quantity, isDivisible, data, isUnspendable);
return new IssueAssetTransactionData(baseTransactionData, assetName, description, quantity, isDivisible, data, isUnspendable);
}
public static int getDataLength(TransactionData transactionData) throws TransformationException {
@ -103,18 +99,16 @@ public class IssueAssetTransactionTransformer extends TransactionTransformer {
transformCommonBytes(transactionData, bytes);
Serialization.serializeAddress(bytes, issueAssetTransactionData.getOwner());
Serialization.serializeSizedString(bytes, issueAssetTransactionData.getAssetName());
Serialization.serializeSizedString(bytes, issueAssetTransactionData.getDescription());
bytes.write(Longs.toByteArray(issueAssetTransactionData.getQuantity()));
bytes.write((byte) (issueAssetTransactionData.getIsDivisible() ? 1 : 0));
bytes.write((byte) (issueAssetTransactionData.isDivisible() ? 1 : 0));
Serialization.serializeSizedString(bytes, issueAssetTransactionData.getData());
bytes.write((byte) (issueAssetTransactionData.getIsUnspendable() ? 1 : 0));
bytes.write((byte) (issueAssetTransactionData.isUnspendable() ? 1 : 0));
bytes.write(Longs.toByteArray(issueAssetTransactionData.getFee()));

View File

@ -41,7 +41,7 @@ public class AssetUtils {
long timestamp = repository.getTransactionRepository().fromSignature(reference).getTimestamp() + 1;
BaseTransactionData baseTransactionData = new BaseTransactionData(timestamp, AssetUtils.txGroupId, reference, account.getPublicKey(), AssetUtils.fee, null);
TransactionData transactionData = new IssueAssetTransactionData(baseTransactionData, account.getAddress(), assetName, "desc", quantity, isDivisible, "{}", false);
TransactionData transactionData = new IssueAssetTransactionData(baseTransactionData, assetName, "desc", quantity, isDivisible, "{}", false);
TransactionUtils.signAndMint(repository, transactionData, account);

View File

@ -14,7 +14,6 @@ public class IssueAssetTestTransaction extends TestTransaction {
public static TransactionData randomTransaction(Repository repository, PrivateKeyAccount account, boolean wantValid) throws DataException {
Random random = new Random();
String owner = account.getAddress();
String assetName = "test-asset-" + random.nextInt(1_000_000);
String description = "random test asset";
final long quantity = 1_000_000L;
@ -22,7 +21,7 @@ public class IssueAssetTestTransaction extends TestTransaction {
String data = AssetUtils.randomData();
final boolean isUnspendable = false;
return new IssueAssetTransactionData(generateBase(account), owner, assetName, description, quantity, isDivisible, data, isUnspendable);
return new IssueAssetTransactionData(generateBase(account), assetName, description, quantity, isDivisible, data, isUnspendable);
}
}

View File

@ -434,7 +434,7 @@ public class GroupApprovalTests extends Common {
long timestamp = repository.getTransactionRepository().fromSignature(reference).getTimestamp() + 1;
BaseTransactionData baseTransactionData = new BaseTransactionData(timestamp, txGroupId, reference, account.getPublicKey(), fee, null);
TransactionData transactionData = new IssueAssetTransactionData(baseTransactionData, account.getAddress(), "test asset", "test asset desc", 1000L, true, "{}", false);
TransactionData transactionData = new IssueAssetTransactionData(baseTransactionData, "test asset", "test asset desc", 1000L, true, "{}", false);
return Transaction.fromData(repository, transactionData);
}

View File

@ -50,9 +50,9 @@
"version": 4,
"timestamp": 0,
"transactions": [
{ "type": "ISSUE_ASSET", "owner": "QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG", "assetName": "QORT", "description": "QORT native coin", "data": "", "quantity": 0, "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "owner": "QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG", "assetName": "Legacy-QORA", "description": "Representative legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "ISSUE_ASSET", "owner": "QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG", "assetName": "QORT-from-QORA", "description": "QORT gained from holding legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "ISSUE_ASSET", "assetName": "QORT", "description": "QORT native coin", "data": "", "quantity": 0, "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "assetName": "Legacy-QORA", "description": "Representative legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "ISSUE_ASSET", "assetName": "QORT-from-QORA", "description": "QORT gained from holding legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "ACCOUNT_FLAGS", "target": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "andMask": -1, "orMask": 1, "xorMask": 0 },
{ "type": "REWARD_SHARE", "minterPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "recipient": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "rewardSharePublicKey": "7PpfnvLSG7y4HPh8hE7KoqAjLCkv7Ui6xw4mKAkbZtox", "sharePercent": 100 },

View File

@ -50,9 +50,9 @@
"version": 4,
"timestamp": 0,
"transactions": [
{ "type": "ISSUE_ASSET", "owner": "QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG", "assetName": "QORT", "description": "QORT native coin", "data": "", "quantity": 0, "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "owner": "QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG", "assetName": "Legacy-QORA", "description": "Representative legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "ISSUE_ASSET", "owner": "QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG", "assetName": "QORT-from-QORA", "description": "QORT gained from holding legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "ISSUE_ASSET", "assetName": "QORT", "description": "QORT native coin", "data": "", "quantity": 0, "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "assetName": "Legacy-QORA", "description": "Representative legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "ISSUE_ASSET", "assetName": "QORT-from-QORA", "description": "QORT gained from holding legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "GENESIS", "recipient": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "amount": "1000000000" },
{ "type": "GENESIS", "recipient": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "amount": "1000000" },

View File

@ -50,9 +50,9 @@
"version": 4,
"timestamp": 0,
"transactions": [
{ "type": "ISSUE_ASSET", "owner": "QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG", "assetName": "QORT", "description": "QORT native coin", "data": "", "quantity": 0, "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "owner": "QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG", "assetName": "Legacy-QORA", "description": "Representative legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "ISSUE_ASSET", "owner": "QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG", "assetName": "QORT-from-QORA", "description": "QORT gained from holding legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "ISSUE_ASSET", "assetName": "QORT", "description": "QORT native coin", "data": "", "quantity": 0, "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "assetName": "Legacy-QORA", "description": "Representative legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "ISSUE_ASSET", "assetName": "QORT-from-QORA", "description": "QORT gained from holding legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "GENESIS", "recipient": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "amount": "1000000000" },
{ "type": "GENESIS", "recipient": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "amount": "1000000" },
@ -64,9 +64,9 @@
{ "type": "CREATE_GROUP", "creatorPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "owner": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "groupName": "dev-group", "description": "developer group", "isOpen": false, "approvalThreshold": "PCT100", "minimumBlockDelay": 0, "maximumBlockDelay": 1440 },
{ "type": "ISSUE_ASSET", "owner": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "assetName": "TEST", "description": "test asset", "data": "", "quantity": 1000000, "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "owner": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "assetName": "OTHER", "description": "other test asset", "data": "", "quantity": 1000000, "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "owner": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "assetName": "GOLD", "description": "gold test asset", "data": "", "quantity": 1000000, "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "issuerPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "assetName": "TEST", "description": "test asset", "data": "", "quantity": 1000000, "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "issuerPublicKey": "C6wuddsBV3HzRrXUtezE7P5MoRXp5m3mEDokRDGZB6ry", "assetName": "OTHER", "description": "other test asset", "data": "", "quantity": 1000000, "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "issuerPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "assetName": "GOLD", "description": "gold test asset", "data": "", "quantity": 1000000, "isDivisible": true, "fee": 0 },
{ "type": "ACCOUNT_FLAGS", "target": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "andMask": -1, "orMask": 1, "xorMask": 0 },
{ "type": "REWARD_SHARE", "minterPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "recipient": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "rewardSharePublicKey": "7PpfnvLSG7y4HPh8hE7KoqAjLCkv7Ui6xw4mKAkbZtox", "sharePercent": 100 },

View File

@ -50,9 +50,9 @@
"version": 4,
"timestamp": 0,
"transactions": [
{ "type": "ISSUE_ASSET", "owner": "QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG", "assetName": "QORT", "description": "QORT native coin", "data": "", "quantity": 0, "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "owner": "QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG", "assetName": "Legacy-QORA", "description": "Representative legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "ISSUE_ASSET", "owner": "QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG", "assetName": "QORT-from-QORA", "description": "QORT gained from holding legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "ISSUE_ASSET", "assetName": "QORT", "description": "QORT native coin", "data": "", "quantity": 0, "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "assetName": "Legacy-QORA", "description": "Representative legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "ISSUE_ASSET", "assetName": "QORT-from-QORA", "description": "QORT gained from holding legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "GENESIS", "recipient": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "amount": "1000000000" },
{ "type": "GENESIS", "recipient": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "amount": "1000000" },
@ -64,9 +64,9 @@
{ "type": "CREATE_GROUP", "creatorPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "owner": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "groupName": "dev-group", "description": "developer group", "isOpen": false, "approvalThreshold": "PCT100", "minimumBlockDelay": 0, "maximumBlockDelay": 1440 },
{ "type": "ISSUE_ASSET", "owner": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "assetName": "TEST", "description": "test asset", "data": "", "quantity": 1000000, "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "owner": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "assetName": "OTHER", "description": "other test asset", "data": "", "quantity": 1000000, "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "owner": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "assetName": "GOLD", "description": "gold test asset", "data": "", "quantity": 1000000, "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "issuerPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "assetName": "TEST", "description": "test asset", "data": "", "quantity": 1000000, "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "issuerPublicKey": "C6wuddsBV3HzRrXUtezE7P5MoRXp5m3mEDokRDGZB6ry", "assetName": "OTHER", "description": "other test asset", "data": "", "quantity": 1000000, "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "issuerPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "assetName": "GOLD", "description": "gold test asset", "data": "", "quantity": 1000000, "isDivisible": true, "fee": 0 },
{ "type": "ACCOUNT_FLAGS", "target": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "andMask": -1, "orMask": 1, "xorMask": 0 },
{ "type": "REWARD_SHARE", "minterPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "recipient": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "rewardSharePublicKey": "7PpfnvLSG7y4HPh8hE7KoqAjLCkv7Ui6xw4mKAkbZtox", "sharePercent": 100 },

View File

@ -50,9 +50,9 @@
"version": 4,
"timestamp": 0,
"transactions": [
{ "type": "ISSUE_ASSET", "owner": "QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG", "assetName": "QORT", "description": "QORT native coin", "data": "", "quantity": 0, "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "owner": "QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG", "assetName": "Legacy-QORA", "description": "Representative legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "ISSUE_ASSET", "owner": "QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG", "assetName": "QORT-from-QORA", "description": "QORT gained from holding legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "ISSUE_ASSET", "assetName": "QORT", "description": "QORT native coin", "data": "", "quantity": 0, "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "assetName": "Legacy-QORA", "description": "Representative legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "ISSUE_ASSET", "assetName": "QORT-from-QORA", "description": "QORT gained from holding legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
{ "type": "GENESIS", "recipient": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "amount": "1000000000" },
{ "type": "GENESIS", "recipient": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "amount": "1000000" },
@ -61,9 +61,9 @@
{ "type": "CREATE_GROUP", "creatorPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "owner": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "groupName": "dev-group", "description": "developer group", "isOpen": false, "approvalThreshold": "PCT100", "minimumBlockDelay": 0, "maximumBlockDelay": 1440 },
{ "type": "ISSUE_ASSET", "owner": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "assetName": "TEST", "description": "test asset", "data": "", "quantity": "1000000", "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "owner": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "assetName": "OTHER", "description": "other test asset", "data": "", "quantity": "1000000", "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "owner": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "assetName": "GOLD", "description": "gold test asset", "data": "", "quantity": "1000000", "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "issuerPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "assetName": "TEST", "description": "test asset", "data": "", "quantity": "1000000", "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "issuerPublicKey": "C6wuddsBV3HzRrXUtezE7P5MoRXp5m3mEDokRDGZB6ry", "assetName": "OTHER", "description": "other test asset", "data": "", "quantity": "1000000", "isDivisible": true, "fee": 0 },
{ "type": "ISSUE_ASSET", "issuerPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "assetName": "GOLD", "description": "gold test asset", "data": "", "quantity": "1000000", "isDivisible": true, "fee": 0 },
{ "type": "ACCOUNT_FLAGS", "target": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "andMask": -1, "orMask": 1, "xorMask": 0 },
{ "type": "REWARD_SHARE", "minterPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "recipient": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "rewardSharePublicKey": "7PpfnvLSG7y4HPh8hE7KoqAjLCkv7Ui6xw4mKAkbZtox", "sharePercent": "100" },