diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 509d7b8fb5..c4f30b9973 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -6418,12 +6418,12 @@ static RPCHelpMan issueasset() { return RPCHelpMan{"issueasset", "\nCreate an asset. Must have funds in wallet to do so. Returns asset hex id.\n" - "For more fine-grained control such as non-empty contract-hashes to commit\n" - "to an issuance policy, see `rawissueasset` RPC call.\n", + "For more fine-grained control such as multiple issuances, see `rawissueasset` RPC call.\n", { {"assetamount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "Amount of asset to generate. Note that the amount is BTC-like, with 8 decimal places."}, {"tokenamount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "Amount of reissuance tokens to generate. Note that the amount is BTC-like, with 8 decimal places. These will allow you to reissue the asset if in wallet using `reissueasset`. These tokens are not consumed during reissuance."}, {"blind", RPCArg::Type::BOOL , /* default */ "true", "Whether to blind the issuances."}, + {"contract_hash", RPCArg::Type::STR_HEX, /* default */ "0000...0000", "Contract hash that is put into issuance definition. Must be 32 bytes worth in hex string form. This will affect the asset id."}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -6459,6 +6459,12 @@ static RPCHelpMan issueasset() bool blind_issuances = request.params.size() < 3 || request.params[2].get_bool(); + // Check for optional contract to hash into definition + uint256 contract_hash; + if (request.params.size() >= 4) { + contract_hash = ParseHashV(request.params[3], "contract_hash"); + } + if (!pwallet->IsLocked()) pwallet->TopUpKeyPool(); @@ -6486,13 +6492,14 @@ static RPCHelpMan issueasset() CAsset dummyasset; IssuanceDetails issuance_details; issuance_details.blind_issuance = blind_issuances; + issuance_details.contract_hash = contract_hash; 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; CHECK_NONFATAL(!tx_ref->vin.empty()); - GenerateAssetEntropy(issuance_details.entropy, tx_ref->vin[0].prevout, uint256()); + GenerateAssetEntropy(issuance_details.entropy, tx_ref->vin[0].prevout, issuance_details.contract_hash); CalculateAsset(asset, issuance_details.entropy); CalculateReissuanceToken(token, issuance_details.entropy, blind_issuances); @@ -7042,7 +7049,7 @@ static const CRPCCommand commands[] = { "wallet", "dumpissuanceblindingkey", &dumpissuanceblindingkey, {"txid", "vin"}}, { "wallet", "signblock", &signblock, {"blockhex", "witnessScript"}}, { "wallet", "listissuances", &listissuances, {"asset"}}, - { "wallet", "issueasset", &issueasset, {"assetamount", "tokenamount", "blind"}}, + { "wallet", "issueasset", &issueasset, {"assetamount", "tokenamount", "blind", "contract_hash"}}, { "wallet", "reissueasset", &reissueasset, {"asset", "assetamount"}}, { "wallet", "destroyamount", &destroyamount, {"asset", "amount", "comment", "verbose"} }, { "hidden", "generatepegoutproof", &generatepegoutproof, {"sumkey", "btcpubkey", "onlinepubkey"} }, diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index d94894f569..f8acd4f3be 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3679,12 +3679,12 @@ bool CWallet::CreateTransactionInternal( uint256 entropy; CAsset asset; CAsset token; - //TODO take optional contract hash // Initial issuance always uses vin[0] - GenerateAssetEntropy(entropy, txNew.vin[0].prevout, uint256()); + GenerateAssetEntropy(entropy, txNew.vin[0].prevout, issuance_details->contract_hash); CalculateAsset(asset, entropy); CalculateReissuanceToken(token, entropy, issuance_details->blind_issuance); CScript blindingScript(CScript() << OP_RETURN << std::vector(txNew.vin[0].prevout.hash.begin(), txNew.vin[0].prevout.hash.end()) << txNew.vin[0].prevout.n); + txNew.vin[0].assetIssuance.assetEntropy = issuance_details->contract_hash; // We're making asset outputs, fill out asset type and issuance input if (asset_index != -1) { txNew.vin[0].assetIssuance.nAmount = txNew.vout[asset_index].nValue; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 4d6bd77ec9..92a260abc8 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -685,7 +685,11 @@ struct CoinSelectionParams struct IssuanceDetails { bool issuing = false; + // Indicated fields. bool blind_issuance = true; + uint256 contract_hash; + + // Calculated fields. CAsset reissuance_asset; CAsset reissuance_token; uint256 entropy; diff --git a/test/functional/feature_issuance.py b/test/functional/feature_issuance.py index 6a9794f7fb..03dc89a9cd 100755 --- a/test/functional/feature_issuance.py +++ b/test/functional/feature_issuance.py @@ -110,7 +110,8 @@ class IssuanceTest(BitcoinTestFramework): assert_equal(len(self.nodes[0].listissuances()), 0) # Unblinded issuance of asset - issued = self.nodes[0].issueasset(1, 1, False) + contract_hash = "deadbeef"*8 + issued = self.nodes[0].issueasset(1, 1, False, contract_hash) balance = self.nodes[0].getwalletinfo()["balance"] assert_equal(balance[issued["asset"]], 1) assert_equal(balance[issued["token"]], 1) @@ -120,7 +121,8 @@ class IssuanceTest(BitcoinTestFramework): self.nodes[0].generate(1) self.sync_all() - issued2 = self.nodes[0].issueasset(2, 1) + contract_hash = "deadbeee"*8 + issued2 = self.nodes[0].issueasset(2, 1, True, contract_hash) test_asset = issued2["asset"] assert_equal(self.nodes[0].getwalletinfo()['balance'][test_asset], Decimal(2)) node1balance = self.nodes[1].getwalletinfo()['balance']