[BROKEN] Add issuance wallet RPCs

This commit is contained in:
Steven Roose 2019-03-20 11:08:36 +00:00
parent a361dda7a3
commit f7920d77ec
No known key found for this signature in database
GPG key ID: 7FC91380BB4CE800
3 changed files with 536 additions and 0 deletions

View file

@ -167,8 +167,17 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "combineblocksigs", 1, "signatures" },
{ "sendtomainchain", 1, "amount" },
{ "sendtomainchain", 2, "subtractfeefromamount" },
{ "dumpissuanceblindingkey", 1, "vin" },
{ "importissuanceblindingkey", 1, "vin" },
{ "rawissueasset", 1, "issuances" },
{ "rawreissueasset", 1, "reissuances" },
{ "getnewblockhex", 0, "required_age" },
{ "testproposedblock", 1, "acceptnonstd" },
{ "issueasset", 0, "assetamount" },
{ "issueasset", 1, "tokenamount" },
{ "issueasset", 2, "blind" },
{ "reissueasset", 1, "assetamount" },
{ "initpegoutwallet", 1, "bip32_counter"},
{ "rawblindrawtransaction", 1, "inputblinder" },
{ "rawblindrawtransaction", 2, "inputamount" },
{ "rawblindrawtransaction", 3, "inputasset" },
@ -177,6 +186,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "blindrawtransaction", 1, "assetcommitments" },
{ "blindrawtransaction", 2, "ignoreblindfail" },
{ "blindrawtransaction", 3, "blind_issuances" },
{ "destroyamount", 1, "amount" },
{ "sendmany", 7 , "output_assets" },
{ "sendmany", 8 , "ignoreblindfail" },
{ "sendtoaddress", 9 , "ignoreblindfail" },

View file

@ -1400,6 +1400,81 @@ UniValue importblindingkey(const JSONRPCRequest& request)
return NullUniValue;
}
UniValue importissuanceblindingkey(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() != 3)
throw std::runtime_error(
"importissuanceblindingkey \"txid\" vin \"blindingkey\"\n"
"\nImports a private blinding key in hex for an asset issuance."
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id of the issuance\n"
"2. \"vin\" (numeric, required) The input number of the issuance in the transaction.\n"
"3. \"blindingkey\" (string, required) The blinding key in hex\n"
"\nExample:\n"
+ HelpExampleCli("importblindingkey", "\"my blinded CT address\" <blindinghex>")
);
LOCK2(cs_main, pwallet->cs_wallet);
if (!request.params[0].isStr() || !IsHex(request.params[0].get_str()) || request.params[0].get_str().size() != 64) {
throw JSONRPCError(RPC_TYPE_ERROR, "First argument must be a txid string");
}
std::string txidstr = request.params[0].get_str();
uint256 txid;
txid.SetHex(txidstr);
uint32_t vindex;
if (!request.params[1].isNum()) {
throw JSONRPCError(RPC_TYPE_ERROR, "vin must be an integer");
}
vindex = request.params[1].get_int();
if (!request.params[2].isStr() || !IsHex(request.params[2].get_str()) || request.params[2].get_str().size() != 64) {
throw JSONRPCError(RPC_TYPE_ERROR, "blinding key must be a hex string of length 64");
}
std::vector<unsigned char> keydata = ParseHex(request.params[2].get_str());
if (keydata.size() != 32) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid hexadecimal key length");
}
CKey key;
key.Set(keydata.begin(), keydata.end(), true);
// Process as issuance key dump
for (std::map<uint256, CWalletTx>::const_iterator it = pwallet->mapWallet.begin(); it != pwallet->mapWallet.end(); ++it) {
const CWalletTx* pcoin = &(*it).second;
if (pcoin->GetHash() != txid) {
continue;
}
if (pcoin->tx->vin.size() <= vindex) {
throw JSONRPCError(RPC_WALLET_ERROR, "Transaction is in wallet but vin does not exist");
}
if (pcoin->tx->vin[vindex].assetIssuance.IsNull()) {
throw JSONRPCError(RPC_WALLET_ERROR, "Transaction input has no issuance");
}
// Import the key in that slot
uint256 keyval;
memcpy(keyval.begin(), &keydata[0], 32);
CScript blindingScript(CScript() << OP_RETURN << std::vector<unsigned char>(pcoin->tx->vin[vindex].prevout.hash.begin(), pcoin->tx->vin[vindex].prevout.hash.end()) << pcoin->tx->vin[vindex].prevout.n);
if (!pwallet->AddSpecificBlindingKey(CScriptID(blindingScript), keyval)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Failed to import blinding key");
}
pwallet->MarkDirty();
return NullUniValue;
}
throw JSONRPCError(RPC_WALLET_ERROR, "Transaction is unknown to wallet.");
}
UniValue dumpblindingkey(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
@ -1443,3 +1518,66 @@ UniValue dumpblindingkey(const JSONRPCRequest& request)
throw JSONRPCError(RPC_WALLET_ERROR, "Blinding key for address is unknown");
}
UniValue dumpissuanceblindingkey(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() != 2)
throw std::runtime_error(
"dumpissuanceblindingkey \"txid\" vin\n"
"\nDumps the private blinding key for an asset issuance in wallet."
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id of the issuance\n"
"2. \"vin\" (numeric, required) The input number of the issuance in the transaction.\n"
"\nResult:\n"
"\"blindingkey\" (string) The blinding key\n"
"\nExample:\n"
+ HelpExampleCli("dumpissuanceblindingkey", "\"<txid>\", 0")
);
LOCK2(cs_main, pwallet->cs_wallet);
if (!request.params[0].isStr() || !IsHex(request.params[0].get_str()) || request.params[0].get_str().size() != 64) {
throw JSONRPCError(RPC_TYPE_ERROR, "First argument must be a txid string");
}
std::string txidstr = request.params[0].get_str();
uint256 txid;
txid.SetHex(txidstr);
uint32_t vindex;
if (!request.params[1].isNum()) {
throw JSONRPCError(RPC_TYPE_ERROR, "vin must be an integer");
}
vindex = request.params[1].get_int();
// Process as issuance key dump
for (std::map<uint256, CWalletTx>::const_iterator it = pwallet->mapWallet.begin(); it != pwallet->mapWallet.end(); ++it) {
const CWalletTx* pcoin = &(*it).second;
if (pcoin->tx->GetHash() != txid) {
continue;
}
if (pcoin->tx->vin.size() <= vindex) {
throw JSONRPCError(RPC_WALLET_ERROR, "Transaction is in wallet but vin does not exist");
}
if (pcoin->tx->vin[vindex].assetIssuance.IsNull()) {
throw JSONRPCError(RPC_WALLET_ERROR, "Transaction input has no issuance");
}
// We can actually deblind the input
if (pcoin->GetIssuanceAmount(vindex, false) != -1 ) {
CScript blindingScript(CScript() << OP_RETURN << std::vector<unsigned char>(pcoin->tx->vin[vindex].prevout.hash.begin(), pcoin->tx->vin[vindex].prevout.hash.end()) << pcoin->tx->vin[vindex].prevout.n);
CKey key;
key = pwallet->GetBlindingKey(&blindingScript);
return HexStr(key.begin(), key.end());
} else {
// We don't know how to deblind this using our wallet
throw JSONRPCError(RPC_WALLET_ERROR, "Unable to unblind issuance with wallet blinding key.");
}
}
throw JSONRPCError(RPC_WALLET_ERROR, "Transaction is unknown to wallet.");
}

View file

@ -5648,6 +5648,386 @@ static UniValue unblindrawtransaction(const JSONRPCRequest& request)
return result;
}
static CTransactionRef SendGenerationTransaction(const CScript& asset_script, const CPubKey &asset_pubkey, const CScript& token_script, const CPubKey &token_pubkey, CAmount asset_amount, CAmount token_amount, IssuanceDetails* issuance_details, CWallet* pwallet)
{
CAsset reissue_token = issuance_details->reissuance_token;
CAmount curBalance = pwallet->GetBalance()[reissue_token];
if (!reissue_token.IsNull() && curBalance <= 0) {
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "No available reissuance tokens in wallet.");
}
// Might need up to 3 change keys: policyAsset, asset, and reissuance token
std::vector<std::unique_ptr<CReserveKey>> change_keys;
for (unsigned int i = 0; i < 3; i++) {
change_keys.push_back(std::unique_ptr<CReserveKey>(new CReserveKey(pwallet)));
}
std::vector<CRecipient> vecSend;
// Signal outputs to skip "funding" with fixed asset numbers 1, 2, ...
// We don't know the asset during initial issuance until inputs are chosen
if (asset_script.size() > 0) {
vecSend.push_back({asset_script, asset_amount, CAsset(uint256S("1")), asset_pubkey, false});
}
if (token_script.size() > 0) {
CRecipient recipient = {token_script, token_amount, CAsset(uint256S("2")), token_pubkey, false};
// We need to select the issuance token(s) to spend
if (!reissue_token.IsNull()) {
recipient.asset = reissue_token;
recipient.nAmount = curBalance; // Or 1?
// If the issuance token *is* the fee asset, subtract fee from this output
if (reissue_token == ::policyAsset) {
recipient.fSubtractFeeFromAmount = true;
}
}
vecSend.push_back(recipient);
}
CAmount nFeeRequired;
int nChangePosRet = -1;
std::string strError;
CCoinControl dummy_control;
BlindDetails blind_details;
CTransactionRef tx_ref(MakeTransactionRef());
if (!pwallet->CreateTransaction(vecSend, tx_ref, change_keys, nFeeRequired, nChangePosRet, strError, dummy_control, true, &blind_details, issuance_details)) {
throw JSONRPCError(RPC_WALLET_ERROR, strError);
}
CValidationState state;
mapValue_t map_value;
if (!pwallet->CommitTransaction(tx_ref, std::move(map_value), {} /* orderForm */, change_keys, g_connman.get(), state, &blind_details)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of the wallet and coins were spent in the copy but not marked as spent here.");
}
return tx_ref;
}
UniValue issueasset(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
throw std::runtime_error(
"issueasset assetamount tokenamount ( blind )\n"
"\nCreate an asset. Must have funds in wallet to do so. Returns asset hex id.\n"
"\nArguments:\n"
"1. \"assetamount\" (numeric or string, required) Amount of asset to generate.\n"
"2. \"tokenamount\" (numeric or string, required) Amount of reissuance tokens to generate. These will allow you to reissue the asset if in wallet using `reissueasset`. These tokens are not consumed during reissuance.\n"
"3. \"blind\" (bool, optional, default=true) Whether to blind the issuances.\n"
"\nResult:\n"
"{ (json object)\n"
" \"txid\":\"<txid>\", (string) Transaction id for issuance.\n"
" \"vin\":\"n\", (numeric) The input position of the issuance in the transaction.\n"
" \"entropy\":\"<entropy>\", (string) Entropy of the asset type.\n"
" \"asset\":\"<asset>\", (string) Asset type for issuance.\n"
" \"token\":\"<token>\", (string) Token type for issuance.\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("issueasset", "10 0")
+ HelpExampleRpc("issueasset", "10, 0")
);
LOCK2(cs_main, pwallet->cs_wallet);
CAmount nAmount = AmountFromValue(request.params[0]);
CAmount nTokens = AmountFromValue(request.params[1]);
if (nAmount == 0 && nTokens == 0) {
throw JSONRPCError(RPC_TYPE_ERROR, "Issuance must have one non-zero component");
}
bool blind_issuances = request.params.size() < 3 || request.params[2].get_bool();
if (!pwallet->IsLocked())
pwallet->TopUpKeyPool();
// Generate a new key that is added to wallet
CPubKey newKey;
CTxDestination asset_dest;
CTxDestination token_dest;
CPubKey asset_dest_blindpub;
CPubKey token_dest_blindpub;
if (nAmount > 0) {
if (!pwallet->GetKeyFromPool(newKey)) {
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
}
asset_dest = PKHash(newKey.GetID());
pwallet->SetAddressBook(asset_dest, "", "receive");
asset_dest_blindpub = pwallet->GetBlindingPubKey(GetScriptForDestination(asset_dest));
}
if (nTokens > 0) {
if (!pwallet->GetKeyFromPool(newKey)) {
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
}
token_dest = PKHash(newKey.GetID());
pwallet->SetAddressBook(token_dest, "", "receive");
token_dest_blindpub = pwallet->GetBlindingPubKey(GetScriptForDestination(token_dest));
}
uint256 dummyentropy;
CAsset dummyasset;
IssuanceDetails issuance_details;
issuance_details.blind_issuance = blind_issuances;
CTransactionRef tx_ref = SendGenerationTransaction(GetScriptForDestination(asset_dest), asset_dest_blindpub, GetScriptForDestination(token_dest), token_dest_blindpub, nAmount, nTokens, &issuance_details, pwallet);
// Calculate asset type, assumes first vin is used for issuance
CAsset asset;
CAsset token;
assert(!tx_ref->vin.empty());
GenerateAssetEntropy(issuance_details.entropy, tx_ref->vin[0].prevout, uint256());
CalculateAsset(asset, issuance_details.entropy);
CalculateReissuanceToken(token, issuance_details.entropy, blind_issuances);
UniValue ret(UniValue::VOBJ);
ret.pushKV("txid", tx_ref->GetHash().GetHex());
ret.pushKV("vin", 0);
ret.pushKV("entropy", issuance_details.entropy.GetHex());
ret.pushKV("asset", asset.GetHex());
ret.pushKV("token", token.GetHex());
return ret;
}
UniValue reissueasset(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() != 2)
throw std::runtime_error(
"reissueasset asset assetamount\n"
"\nCreate more of an already issued asset. Must have reissuance token in wallet to do so. Reissuing does not affect your reissuance token balance, only asset.\n"
"\nArguments:\n"
"1. \"asset\" (string, required) The asset you want to re-issue. The corresponding token must be in your wallet.\n"
"2. \"assetamount\" (numeric or string, required) Amount of additional asset to generate.\n"
"\nResult:\n"
"{ (json object)\n"
" \"txid\":\"<txid>\", (string) Transaction id for issuance.\n"
" \"vin\":\"n\", (numeric) The input position of the issuance in the transaction.\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("reissueasset", "<asset> 0")
+ HelpExampleRpc("reissueasset", "<asset>, 0")
);
LOCK2(cs_main, pwallet->cs_wallet);
std::string assetstr = request.params[0].get_str();
CAsset asset = GetAssetFromString(assetstr);
CAmount nAmount = AmountFromValue(request.params[1]);
if (nAmount <= 0) {
throw JSONRPCError(RPC_TYPE_ERROR, "Reissuance must create a non-zero amount.");
}
if (!pwallet->IsLocked()) {
pwallet->TopUpKeyPool();
}
// Find the entropy and reissuance token in wallet
IssuanceDetails issuance_details;
issuance_details.reissuance_asset = asset;
std::map<uint256, std::pair<CAsset, CAsset> > tokenMap = pwallet->GetReissuanceTokenTypes();
for (const auto& it : tokenMap) {
if (it.second.second == asset) {
issuance_details.entropy = it.first;
issuance_details.reissuance_token = it.second.first;
}
if (it.second.first == asset) {
throw JSONRPCError(RPC_WALLET_ERROR, "Asset given is a reissuance token type and can not be reissued.");
}
}
if (issuance_details.reissuance_token.IsNull()) {
throw JSONRPCError(RPC_WALLET_ERROR, "Asset reissuance token definition could not be found in wallet.");
}
// Add destination for the to-be-created asset
CPubKey newAssetKey;
if (!pwallet->GetKeyFromPool(newAssetKey)) {
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
}
CTxDestination asset_dest = PKHash(newAssetKey.GetID());
pwallet->SetAddressBook(asset_dest, "", "receive");
CPubKey asset_dest_blindpub = pwallet->GetBlindingPubKey(GetScriptForDestination(asset_dest));
// Add destination for tokens we are moving
CPubKey newTokenKey;
if (!pwallet->GetKeyFromPool(newTokenKey)) {
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
}
CTxDestination token_dest = PKHash(newTokenKey.GetID());
pwallet->SetAddressBook(token_dest, "", "receive");
CPubKey token_dest_blindpub = pwallet->GetBlindingPubKey(GetScriptForDestination(token_dest));
// Attempt a send.
CTransactionRef tx_ref = SendGenerationTransaction(GetScriptForDestination(asset_dest), asset_dest_blindpub, GetScriptForDestination(token_dest), token_dest_blindpub, nAmount, -1, &issuance_details, pwallet);
assert(!tx_ref->vin.empty());
UniValue obj(UniValue::VOBJ);
obj.pushKV("txid", tx_ref->GetHash().GetHex());
for (uint64_t i = 0; i < tx_ref->vin.size(); i++) {
if (!tx_ref->vin[i].assetIssuance.IsNull()) {
obj.pushKV("vin", i);
break;
}
}
return obj;
}
UniValue listissuances(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() > 1)
throw std::runtime_error(
"listissuances ( asset ) \n"
"\nList all issuances known to the wallet for the given asset, or for all issued assets if none provided.\n"
"\nArguments:\n"
"1. \"asset\" (string, optional) The asset whose issaunces you wish to list. Accepts either the asset hex or the locally assigned asset label.\n"
"\nResult:\n"
"[ (json array of objects)\n"
" {\n"
" \"txid\":\"<txid>\", (string) Transaction id for issuance.\n"
" \"entropy\":\"<entropy>\" (string) Entropy of the asset type.\n"
" \"asset\":\"<asset>\", (string) Asset type for issuance if known.\n"
" \"assetlabel\":\"<assetlabel>\", (string) Asset label for issuance if set.\n"
" \"token\":\"<token>\", (string) Token type for issuance.\n"
" \"vin\":\"n\", (numeric) The input position of the issuance in the transaction.\n"
" \"assetamount\":\"X.XX\", (numeric) The amount of asset issued. Is -1 if blinded and unknown to wallet.\n"
" \"tokenamount\":\"X.XX\", (numeric) The reissuance token amount issued. Is -1 if blinded and unknown to wallet.\n"
" \"isreissuance\":\"<bool>\", (bool) True if this is a reissuance.\n"
" \"assetblinds\":\"<blinder>\" (string) Hex blinding factor for asset amounts.\n"
" \"tokenblinds\":\"<blinder>\" (string) Hex blinding factor for token amounts.\n"
" }\n"
" ,...\n"
"]\n"
"\"\" (array) List of transaction issuances and information in wallet\n"
+ HelpExampleCli("listissuances", "<asset>")
+ HelpExampleRpc("listissuances", "<asset>")
);
LOCK2(cs_main, pwallet->cs_wallet);
std::string assetstr;
CAsset asset_filter;
if (request.params.size() > 0) {
assetstr = request.params[0].get_str();
asset_filter = GetAssetFromString(assetstr);
}
UniValue issuancelist(UniValue::VARR);
for (const auto& it : pwallet->mapWallet) {
const CWalletTx* pcoin = &it.second;
CAsset asset;
CAsset token;
uint256 entropy;
for (uint64_t vinIndex = 0; vinIndex < pcoin->tx->vin.size(); vinIndex++) {
UniValue item(UniValue::VOBJ);
const CAssetIssuance& issuance = pcoin->tx->vin[vinIndex].assetIssuance;
if (issuance.IsNull()) {
continue;
}
if (issuance.assetBlindingNonce.IsNull()) {
GenerateAssetEntropy(entropy, pcoin->tx->vin[vinIndex].prevout, issuance.assetEntropy);
CalculateAsset(asset, entropy);
// Null is considered explicit
CalculateReissuanceToken(token, entropy, issuance.nAmount.IsCommitment());
item.pushKV("isreissuance", false);
item.pushKV("token", token.GetHex());
CAmount itamount = pcoin->GetIssuanceAmount(vinIndex, true);
item.pushKV("tokenamount", (itamount == -1 ) ? -1 : ValueFromAmount(itamount));
item.pushKV("tokenblinds", pcoin->GetIssuanceBlindingFactor(vinIndex, true).GetHex());
item.pushKV("entropy", entropy.GetHex());
} else {
CalculateAsset(asset, issuance.assetEntropy);
item.pushKV("isreissuance", true);
item.pushKV("entropy", issuance.assetEntropy.GetHex());
}
item.pushKV("txid", pcoin->tx->GetHash().GetHex());
item.pushKV("vin", vinIndex);
item.pushKV("asset", asset.GetHex());
const std::string label = gAssetsDir.GetLabel(asset);
if (label != "") {
item.pushKV("assetlabel", label);
}
CAmount iaamount = pcoin->GetIssuanceAmount(vinIndex, false);
item.pushKV("assetamount", (iaamount == -1 ) ? -1 : ValueFromAmount(iaamount));
item.pushKV("assetblinds", pcoin->GetIssuanceBlindingFactor(vinIndex, false).GetHex());
if (!asset_filter.IsNull() && asset_filter != asset) {
continue;
}
issuancelist.push_back(item);
}
}
return issuancelist;
}
UniValue destroyamount(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
throw std::runtime_error(
"destroyamount asset amount ( \"comment\" )\n"
"\nDestroy an amount of a given asset.\n\n"
"\nArguments:\n"
"1. \"asset\" (string, required) Hex asset id or asset label to destroy.\n"
"2. \"amount\" (numeric or string, required) The amount to destroy (8 decimals above the minimal unit).\n"
"3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
" This is not part of the transaction, just kept in your wallet.\n"
"\nResult:\n"
"\"transactionid\" (string) The transaction id.\n"
"\nExamples:\n"
+ HelpExampleCli("destroyamount", "\"bitcoin\" 100")
+ HelpExampleCli("destroyamount", "\"bitcoin\" 100 \"destroy assets\"")
+ HelpExampleRpc("destroyamount", "\"bitcoin\" 100 \"destroy assets\"")
);
LOCK2(cs_main, pwallet->cs_wallet);
std::string strasset = request.params[0].get_str();
CAsset asset = GetAssetFromString(strasset);
CAmount nAmount = AmountFromValue(request.params[1]);
if (nAmount <= 0) {
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount to destroy");
}
mapValue_t mapValue;
if (request.params.size() > 2 && !request.params[2].isNull() && !request.params[2].get_str().empty()) {
mapValue["comment"] = request.params[2].get_str();
}
EnsureWalletIsUnlocked(pwallet);
NullData nulldata;
CTxDestination address(nulldata);
CCoinControl no_coin_control; // This is a deprecated API
CTransactionRef tx = SendMoney(pwallet, address, nAmount, asset, false, no_coin_control, std::move(mapValue), true);
return tx->GetHash().GetHex();
}
// END ELEMENTS commands
//
@ -5655,7 +6035,9 @@ static UniValue unblindrawtransaction(const JSONRPCRequest& request)
UniValue abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp
UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp
UniValue importblindingkey(const JSONRPCRequest& request); // in rpcdump.cpp
UniValue importissuanceblindingkey(const JSONRPCRequest& request); // in rpcdump.cpp
UniValue dumpblindingkey(const JSONRPCRequest& request); // in rpcdump.cpp
UniValue dumpissuanceblindingkey(const JSONRPCRequest& request); // in rpcdump.cpp
UniValue importprivkey(const JSONRPCRequest& request);
UniValue importaddress(const JSONRPCRequest& request);
UniValue importpubkey(const JSONRPCRequest& request);
@ -5736,8 +6118,14 @@ static const CRPCCommand commands[] =
{ "wallet", "initpegoutwallet", &initpegoutwallet, {"bitcoin_descriptor", "bip32_counter", "liquid_pak"} },
{ "wallet", "getwalletpakinfo", &getwalletpakinfo, {} },
{ "wallet", "importblindingkey", &importblindingkey, {"address", "hexkey", "key_is_master"}},
{ "wallet", "importissuanceblindingkey", &importissuanceblindingkey, {"txid", "vin", "blindingkey"}},
{ "wallet", "dumpblindingkey", &dumpblindingkey, {"address"}},
{ "wallet", "dumpissuanceblindingkey", &dumpissuanceblindingkey, {"txid", "vin"}},
{ "wallet", "signblock", &signblock, {"blockhex"}},
{ "wallet", "listissuances", &listissuances, {"asset"}},
{ "wallet", "issueasset", &issueasset, {"assetamount", "tokenamount", "blind"}},
{ "wallet", "reissueasset", &reissueasset, {"asset, assetamount"}},
{ "wallet", "destroyamount", &destroyamount, {"asset", "amount", "comment"} },
};
// clang-format on