diff --git a/cyphernodeconf_docker/prompters/930_elements.js b/cyphernodeconf_docker/prompters/930_elements.js index d8311825..40cf9c7f 100644 --- a/cyphernodeconf_docker/prompters/930_elements.js +++ b/cyphernodeconf_docker/prompters/930_elements.js @@ -15,7 +15,16 @@ module.exports = { return name; }, prompts: function( utils ) { - return []; + return [ + { + when: function(props) { return props.features.indexOf('elements') !== -1 }, + type: 'input', + name: 'liquid_explorer_url', + default: utils.getDefault( 'liquid_explorer_url' ), + message: prefix()+'Liquid explorer base URL?'+utils.getHelp('liquid_explorer_url'), + filter: utils.trimFilter, + } + ]; }, env: function( props ) { return 'VAR0=VALUE0\nVAR1=VALUE1' diff --git a/cyphernodeconf_docker/schema/config-v0.2.6.liquid.json b/cyphernodeconf_docker/schema/config-v0.2.6.liquid.json index 5a8517de..4b42b290 100644 --- a/cyphernodeconf_docker/schema/config-v0.2.6.liquid.json +++ b/cyphernodeconf_docker/schema/config-v0.2.6.liquid.json @@ -147,7 +147,8 @@ "then": { "required": [ "elements_datapath", - "elements_expose" + "elements_expose", + "liquid_explorer_url" ] } }, @@ -672,6 +673,15 @@ false ] }, + "liquid_explorer_url": { + "$id": "#/properties/liquid_explorer_url", + "type": "string", + "title": "Liquid explorer URL", + "examples": [ + "https://liquid.network", + "https://liquid.bullbitcoin.com" + ] + }, "gatekeeper_expose": { "$id": "#/properties/gatekeeper_expose", "type": "boolean", diff --git a/cyphernodeconf_docker/templates/gatekeeper/api.properties b/cyphernodeconf_docker/templates/gatekeeper/api.properties index 56759dd8..0d0a83aa 100644 --- a/cyphernodeconf_docker/templates/gatekeeper/api.properties +++ b/cyphernodeconf_docker/templates/gatekeeper/api.properties @@ -49,6 +49,7 @@ action_elements_unwatch=watcher action_elements_gettransaction=watcher action_elements_getbestblockhash=watcher action_elements_getblockchaininfo=watcher +action_elements_getunblindedurl=watcher action_elements_getmempoolinfo=watcher action_elements_watchtxid=watcher action_elements_unwatchtxid=watcher diff --git a/cyphernodeconf_docker/templates/proxy/proxy.env b/cyphernodeconf_docker/templates/proxy/proxy.env index 0c807e82..38f2d059 100644 --- a/cyphernodeconf_docker/templates/proxy/proxy.env +++ b/cyphernodeconf_docker/templates/proxy/proxy.env @@ -42,4 +42,5 @@ WATCHER_ELEMENTS_NODE_DEFAULT_WALLET=watching01.dat WATCHER_ELEMENTS_NODE_XPUB_WALLET=xpubwatching01.dat WATCHER_ELEMENTS_NODE_RPC_USER=<%= bitcoin_rpcuser %>:<%= bitcoin_rpcpassword %> WATCHER_ELEMENTS_NODE_RPC_CFG=/tmp/watcher_elementsnode_curlcfg.properties +LIQUID_EXPLORER_URL=<%= liquid_explorer_url %> <% } %> \ No newline at end of file diff --git a/proxy_docker/app/script/elements_blockchainrpc.sh b/proxy_docker/app/script/elements_blockchainrpc.sh index 09cdf2f6..d6a10580 100644 --- a/proxy_docker/app/script/elements_blockchainrpc.sh +++ b/proxy_docker/app/script/elements_blockchainrpc.sh @@ -183,3 +183,77 @@ elements_getaddressinfo() { fi return $? } + +elements_getunblindedurl() { + trace "Entering elements_getunblindedurl()..." + + local txid=${1} + trace "[elements_getunblindedurl] txid=${txid}" + + # Validate txid format (64 hex characters) + if [ -z "${txid}" ]; then + echo "{\"error\":\"txid is required\"}" + return 1 + fi + if ! echo "${txid}" | grep -qE '^[a-fA-F0-9]{64}$'; then + echo "{\"error\":\"Invalid txid format\"}" + return 1 + fi + + local base_url=${LIQUID_EXPLORER_URL} + trace "[elements_getunblindedurl] base_url=${base_url}" + + if [ -z "${base_url}" ]; then + echo "{\"error\":\"LIQUID_EXPLORER_URL not configured\"}" + return 1 + fi + + # Get transaction details from spender node (has blinding data) + local tx_response + tx_response=$(elements_get_transaction "${txid}" "spender") + local returncode=$? + trace_rc ${returncode} + + if [ "${returncode}" -ne 0 ]; then + echo "{\"error\":\"Failed to get transaction\"}" + return ${returncode} + fi + + local tx_result + tx_result=$(echo "${tx_response}" | jq -r '.result') + + if [ "${tx_result}" = "null" ] || [ -z "${tx_result}" ]; then + echo "{\"error\":\"Transaction not found\"}" + return 1 + fi + + # Extract blinding data from details array + # Filter for entries with valid blinding data (non-zero blinders) + local blinded_fragment + blinded_fragment=$(echo "${tx_response}" | jq -r ' + .result.details + | map(select(.amountblinder != null and .assetblinder != null and .asset != null)) + | map(select(.amountblinder != "0000000000000000000000000000000000000000000000000000000000000000")) + | map( + (if .amount < 0 then (-.amount) else .amount end) * 100000000 | floor | tostring + + "," + .asset + + "," + .amountblinder + + "," + .assetblinder + ) + | join(",") + ') + + trace "[elements_getunblindedurl] blinded_fragment=${blinded_fragment}" + + local url + if [ -n "${blinded_fragment}" ] && [ "${blinded_fragment}" != "null" ]; then + url="${base_url}/tx/${txid}#blinded=${blinded_fragment}" + else + url="${base_url}/tx/${txid}" + fi + + trace "[elements_getunblindedurl] url=${url}" + + echo "{\"url\":\"${url}\",\"txid\":\"${txid}\"}" + return 0 +} diff --git a/proxy_docker/app/script/requesthandler.sh b/proxy_docker/app/script/requesthandler.sh index 0b9586a9..2ebaabf5 100644 --- a/proxy_docker/app/script/requesthandler.sh +++ b/proxy_docker/app/script/requesthandler.sh @@ -1097,6 +1097,13 @@ main() { response=$(elements_get_blockchain_info) returncode=$? ;; + elements_getunblindedurl) + # GET http://192.168.111.152:8080/elements_getunblindedurl/{txid} + + txid=$(echo "${line}" | cut -d ' ' -f2 | cut -d '/' -f3) + response=$(elements_getunblindedurl "${txid}") + returncode=$? + ;; elements_generatetoaddress) # GET with no parameters ==> http://192.168.111.152:8080/elements_generatetoaddress # POST http://192.168.111.152:8080/elements_generatetoaddress