Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
528 changes: 385 additions & 143 deletions src/assets/assets.cpp

Large diffs are not rendered by default.

24 changes: 11 additions & 13 deletions src/assets/assets.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,6 @@ struct CAssetOutputEntry;
// 50000 * 82 Bytes == 4.1 Mb
#define MAX_CACHE_ASSETS_SIZE 50000

enum AssetType
{
ROOT,
OWNER,
SUB,
UNIQUE,
MSGCHANNEL,
VOTE,
INVALID
};

class CAssets {
public:
std::map<std::string, std::set<COutPoint> > mapMyUnspentAssets; // Asset Name -> COutPoint
Expand Down Expand Up @@ -309,10 +298,13 @@ CAmount GetIssueAssetBurnAmount();
CAmount GetReissueAssetBurnAmount();
CAmount GetIssueSubAssetBurnAmount();
CAmount GetIssueUniqueAssetBurnAmount();
CAmount GetBurnAmount(const AssetType type);
std::string GetBurnAddress(const AssetType type);

bool IsAssetNameValid(const std::string& name);
bool IsAssetNameValid(const std::string& name, AssetType& assetType);
bool IsAssetNameAnOwner(const std::string& name);
std::string GetParentName(const std::string& name); // Gets the parent name of a subasset TEST/TESTSUB would return TEST

bool IsAssetNameSizeValid(const std::string& name);

Expand All @@ -323,18 +315,22 @@ bool OwnerFromTransaction(const CTransaction& tx, std::string& ownerName, std::s
bool ReissueAssetFromTransaction(const CTransaction& tx, CReissueAsset& reissue, std::string& strAddress);

bool TransferAssetFromScript(const CScript& scriptPubKey, CAssetTransfer& assetTransfer, std::string& strAddress);
bool AssetFromScript(const CScript& scriptPubKey, CNewAsset& assetTransfer, std::string& strAddress);
bool AssetFromScript(const CScript& scriptPubKey, CNewAsset& asset, std::string& strAddress);
bool OwnerAssetFromScript(const CScript& scriptPubKey, std::string& assetName, std::string& strAddress);
bool ReissueAssetFromScript(const CScript& scriptPubKey, CReissueAsset& reissue, std::string& strAddress);

bool CheckIssueBurnTx(const CTxOut& txOut);
bool CheckIssueBurnTx(const CTxOut& txOut, const AssetType& type);
bool CheckReissueBurnTx(const CTxOut& txOut);

bool CheckIssueDataTx(const CTxOut& txOut);
bool CheckOwnerDataTx(const CTxOut& txOut);
bool CheckReissueDataTx(const CTxOut& txOut);
bool CheckTransferOwnerTx(const CTxOut& txOut);

bool IsScriptNewAsset(const CScript& scriptPubKey, int& nStartingIndex);
bool IsScriptOwnerAsset(const CScript& scriptPubKey, int& nStartingIndex);
bool IsScriptReissueAsset(const CScript& scriptPubKey, int& nStartingIndex);
bool IsScriptTransferAsset(const CScript& scriptPubKey, int& nStartingIndex);
bool IsScriptNewAsset(const CScript& scriptPubKey);
bool IsScriptOwnerAsset(const CScript& scriptPubKey);
bool IsScriptReissueAsset(const CScript& scriptPubKey);
Expand All @@ -360,6 +356,8 @@ bool GetMyAssetBalance(CAssetsCache& cache, const std::string& assetName, CAmoun
bool GetMyAssetBalances(CAssetsCache& cache, const std::vector<std::string>& assetNames, std::map<std::string, CAmount>& balances);
bool GetMyAssetBalances(CAssetsCache& cache, std::map<std::string, CAmount>& balances);

bool VerifyAssetOwner(const std::string& asset_name, std::set<COutPoint>& myOwnerOutPoints, std::pair<int, std::string>& error);

std::string DecodeIPFS(std::string encoded);
std::string EncodeIPFS(std::string decoded);

Expand Down
13 changes: 13 additions & 0 deletions src/assets/assettypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@

class CAssetsCache;


enum AssetType
{
ROOT,
OWNER,
SUB,
UNIQUE,
MSGCHANNEL,
VOTE,
INVALID,
REISSUE
};

class CNewAsset {
public:
std::string strName; // MAX 31 Bytes
Expand Down
2 changes: 1 addition & 1 deletion src/coins.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class Coin
}

bool IsAsset() const {
return out.scriptPubKey.IsTransferAsset() || out.scriptPubKey.IsNewAsset() || out.scriptPubKey.IsOwnerAsset() || out.scriptPubKey.IsReissueAsset();
return out.scriptPubKey.IsAssetScript();
}

size_t DynamicMemoryUsage() const {
Expand Down
5 changes: 3 additions & 2 deletions src/consensus/tx_verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, CAssetsCa
return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge");

/** RVN START */
if (!AreAssetsDeployed() && txout.scriptPubKey.IsAsset() && !fReindex)
if (!AreAssetsDeployed() && txout.scriptPubKey.IsAssetScript() && !fReindex)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-is-asset-and-asset-not-active");

// Check for transfers that don't meet the assets units only if the assetCache is not null
Expand Down Expand Up @@ -388,8 +388,9 @@ bool Consensus::CheckTxAssets(const CTransaction& tx, CValidationState& state, c
}

// Check the input values and the output values
if (totalOutputs.size() != totalInputs.size())
if (totalOutputs.size() != totalInputs.size()) {
return state.DoS(100, false, REJECT_INVALID, "bad-tx-asset-inputs-size-does-not-match-outputs-size");
}

for (const auto& outValue : totalOutputs) {
if (!totalInputs.count(outValue.first))
Expand Down
135 changes: 131 additions & 4 deletions src/rpc/assets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ UniValue issue(const JSONRPCRequest& request)
"3. \"to_address\" (string), optional, default=\"\"), address asset will be sent to, if it is empty, address will be generated for you\n"
"4. \"change_address\" (string), optional, default=\"\"), address the the rvn change will be sent to, if it is empty, change address will be generated for you\n"
"5. \"units\" (integer, optional, default=8, min=0, max=8), the number of decimals precision for the asset (0 for whole units (\"1\"), 8 for max precision (\"1.00000000\")\n"
"6. \"reissuable\" (boolean, optional, default=false), whether future reissuance is allowed\n"
"6. \"reissuable\" (boolean, optional, default=true), whether future reissuance is allowed\n"
"7. \"has_ipfs\" (boolean, optional, default=false), whether ifps hash is going to be added to the asset\n"
"8. \"ipfs_hash\" (string, optional but required if has_ipfs = 1), an ipfs hash\n"

Expand Down Expand Up @@ -146,7 +146,7 @@ UniValue issue(const JSONRPCRequest& request)
int units = 8;
if (request.params.size() > 4)
units = request.params[4].get_int();
bool reissuable = false;
bool reissuable = true;
if (request.params.size() > 5)
reissuable = request.params[5].get_bool();

Expand Down Expand Up @@ -179,6 +179,132 @@ UniValue issue(const JSONRPCRequest& request)
return result;
}

UniValue issuesubasset(const JSONRPCRequest& request)
{
if (request.fHelp || !AreAssetsDeployed() || request.params.size() < 3 || request.params.size() > 9)
throw std::runtime_error(
"issuesubasset \"parent_asset_name\" \"sub_asset_name\" qty \"( to_address )\" \"( change_address )\" ( units ) ( reissuable ) ( has_ipfs ) \"( ipfs_hash )\"\n"
+ AssetActivationWarning() +
"\nIssue a subasset with unique name.\n"
"Unit as the number of decimals precision for the subasset (0 for whole units (\"1\"), 8 for max precision (\"1.00000000\")\n"
"Qty should be whole number.\n"
"Reissuable is true/false for whether additional units can be issued by the original issuer.\n"

"\nArguments:\n"
"1. \"parent_asset_name\" (string, required) the parent asset name that is owned by this wallet\n"
"2. \"sub_asset_name\" (string, required) a unique name\n"
"3. \"qty\" (integer, required) the number of units to be issued\n"
"4. \"to_address\" (string), optional, default=\"\"), address subasset will be sent to, if it is empty, address will be generated for you\n"
"5. \"change_address\" (string), optional, default=\"\"), address the the rvn change will be sent to, if it is empty, change address will be generated for you\n"
"6. \"units\" (integer, optional, default=8, min=0, max=8), the number of decimals precision for the asset (0 for whole units (\"1\"), 8 for max precision (\"1.00000000\")\n"
"7. \"reissuable\" (boolean, optional, default=true), whether future reissuance is allowed\n"
"8. \"has_ipfs\" (boolean, optional, default=false), whether ifps hash is going to be added to the asset\n"
"9. \"ipfs_hash\" (string, optional but required if has_ipfs = 1), an ipfs hash\n"

"\nResult:\n"
"\"txid\" (string) The transaction id\n"

"\nExamples:\n"
+ HelpExampleCli("issuesubasset", "\"myassetname\" \"subassetname\" 1000")
+ HelpExampleCli("issuesubasset", "\"myassetname\" \"subassetname\" 1000 \"myaddress\"")
+ HelpExampleCli("issuesubasset", "\"myassetname\" \"subassetname\" 1000 \"myaddress\" \"changeaddress\" 4")
+ HelpExampleCli("issuesubasset", "\"myassetname\" \"subassetname\" 1000 \"myaddress\" \"changeaddress\" 2 true")
);

CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}

ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);

EnsureWalletIsUnlocked(pwallet);

std::string parent_asset_name = request.params[0].get_str();
std::string asset_name = request.params[1].get_str();
CAmount nAmount = AmountFromValue(request.params[2]);

std::string address = "";
if (request.params.size() > 3)
address = request.params[3].get_str();

if (!address.empty()) {
CTxDestination destination = DecodeDestination(address);
if (!IsValidDestination(destination)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Raven address: ") + address);
}
} else {
// Create a new address
std::string strAccount;

if (!pwallet->IsLocked()) {
pwallet->TopUpKeyPool();
}

// Generate a new key that is added to wallet
CPubKey newKey;
if (!pwallet->GetKeyFromPool(newKey)) {
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
}
CKeyID keyID = newKey.GetID();

pwallet->SetAddressBook(keyID, strAccount, "receive");

address = EncodeDestination(keyID);
}

std::string changeAddress = "";
if (request.params.size() > 4)
changeAddress = request.params[4].get_str();
if (!changeAddress.empty()) {
CTxDestination destination = DecodeDestination(changeAddress);
if (!IsValidDestination(destination)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
std::string("Invalid Change Address: Invalid Raven address: ") + changeAddress);
}
}

int units = 8;
if (request.params.size() > 5)
units = request.params[5].get_int();
bool reissuable = true;
if (request.params.size() > 6)
reissuable = request.params[6].get_bool();

bool has_ipfs = false;
if (request.params.size() > 7)
has_ipfs = request.params[7].get_bool();

std::string ipfs_hash = "";
if (request.params.size() > 8 && has_ipfs)
ipfs_hash = request.params[8].get_str();

std::string strFullSubAssetName = parent_asset_name + "/" + asset_name;
CNewAsset asset(strFullSubAssetName, nAmount, units, reissuable ? 1 : 0, has_ipfs ? 1 : 0, DecodeIPFS(ipfs_hash));

CReserveKey reservekey(pwallet);
CWalletTx transaction;
CAmount nRequiredFee;
std::pair<int, std::string> error;

// Create the Transaction
if (!CreateAssetTransaction(pwallet, asset, address, error, changeAddress, transaction, reservekey, nRequiredFee))
throw JSONRPCError(error.first, error.second);

// Send the Transaction to the network
std::string txid;
if (!SendAssetTransaction(pwallet, transaction, reservekey, error, txid))
throw JSONRPCError(error.first, error.second);

UniValue result(UniValue::VARR);
result.push_back(txid);
return result;
}




UniValue listassetbalancesbyaddress(const JSONRPCRequest& request)
{
if (request.fHelp || !AreAssetsDeployed() || request.params.size() < 1)
Expand Down Expand Up @@ -513,8 +639,8 @@ UniValue transfer(const JSONRPCRequest& request)

"\nArguments:\n"
"1. \"asset_name\" (string, required) name of asset\n"
"3. \"qty\" (number, required) number of assets you want to send to the address\n"
"2. \"to_address\" (string, required) address to send the asset to\n"
"2. \"qty\" (number, required) number of assets you want to send to the address\n"
"3. \"to_address\" (string, required) address to send the asset to\n"

"\nResult:\n"
"txid"
Expand Down Expand Up @@ -745,6 +871,7 @@ static const CRPCCommand commands[] =
{ // category name actor (function) argNames
// ----------- ------------------------ ----------------------- ----------
{ "assets", "issue", &issue, {"asset_name","qty","to_address","change_address","units","reissuable","has_ipfs","ipfs_hash"} },
{ "assets", "issuesubasset", &issuesubasset, {"parent_asset_name","asset_name","qty","to_address","change_address","units","reissuable","has_ipfs","ipfs_hash"} },
{ "assets", "listassetbalancesbyaddress", &listassetbalancesbyaddress, {"address"} },
{ "assets", "getassetdata", &getassetdata, {"asset_name"}},
{ "assets", "listmyassets", &listmyassets, {"asset", "verbose", "count", "start"}},
Expand Down
4 changes: 4 additions & 0 deletions src/rpc/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "issue", 4, "units" },
{ "issue", 5, "reissuable" },
{ "issue", 6, "has_ipfs" },
{ "issuesubasset", 2, "qty" },
{ "issuesubasset", 5, "units" },
{ "issuesubasset", 6, "reissuable" },
{ "issuesubasset", 7, "has_ipfs" },
{ "transfer", 1, "qty"},
{ "reissue", 1, "qty"},
{ "reissue", 4, "reissuable"},
Expand Down
Loading