Open adambor opened 2 weeks ago
You needn't set the nftAddress, it's only for multi-address wallet, such as Xverse, hiro. Please refer to https://docs.unisat.io/dev/unisat-developer-center/unisat-marketplace/brc20-marketplace to learn how to use the parameters.
I'm actually trying to do it too, but receiving problem:
{
btcAddress: 'bc1q5fqwlf88dtu9qa2jkvwhjr94k07cerfau3mh9s',
nftAddress: 'bc1p7n462ru9wtfgclwedfgp0eqe6w40pjwt7wvkxgdmzue2y6ptdkvsuzzmu2',
sign: '6b96d3f0165b11b448163825f67a894e8cb1e2fcaa44f203ce6f704c77c84c1c3b73735840b75c25b9d8b11c1448785c5f10f0d5a746f0482b95a4d2fc9f94d3'
}
{
code: -1,
msg: 'Signature.fromCompact: Expected 64-byte hex',
data: null
}
Can you help? @cloud6605
You needn't set the nftAddress, it's only for multi-address wallet, such as Xverse, hiro. Please refer to https://docs.unisat.io/dev/unisat-developer-center/unisat-marketplace/brc20-marketplace to learn how to use the parameters.
Well, I guess I need to use the nftAddress param... My use case:
A HD wallet with many different UTXOs across many different p2wpkh addresses for payments & single derived p2tr address for ordinals. So I need to pay for the ordinal with the p2wpkh utxos - using the "utxos" param (and receive change to p2wpkh change address - using the "address" param) & receive the ordinal to the single derived p2tr address - using the "nftAddress" param. How do I accomplish this with the API?
I'm actually trying to do it too, but receiving problem:
{ btcAddress: 'bc1q5fqwlf88dtu9qa2jkvwhjr94k07cerfau3mh9s', nftAddress: 'bc1p7n462ru9wtfgclwedfgp0eqe6w40pjwt7wvkxgdmzue2y6ptdkvsuzzmu2', sign: '6b96d3f0165b11b448163825f67a894e8cb1e2fcaa44f203ce6f704c77c84c1c3b73735840b75c25b9d8b11c1448785c5f10f0d5a746f0482b95a4d2fc9f94d3' } { code: -1, msg: 'Signature.fromCompact: Expected 64-byte hex', data: null }
Can you help? @cloud6605
What's the endpoint you are using for this? Any pointers to docs about this procedure?
I'm actually trying to do it too, but receiving problem:
{ btcAddress: 'bc1q5fqwlf88dtu9qa2jkvwhjr94k07cerfau3mh9s', nftAddress: 'bc1p7n462ru9wtfgclwedfgp0eqe6w40pjwt7wvkxgdmzue2y6ptdkvsuzzmu2', sign: '6b96d3f0165b11b448163825f67a894e8cb1e2fcaa44f203ce6f704c77c84c1c3b73735840b75c25b9d8b11c1448785c5f10f0d5a746f0482b95a4d2fc9f94d3' } { code: -1, msg: 'Signature.fromCompact: Expected 64-byte hex', data: null }
Can you help? @cloud6605
What's the endpoint you are using for this? Any pointers to docs about this procedure?
Bind btcAddress and nftAddress.
I'm actually trying to do it too, but receiving problem:
{ btcAddress: 'bc1q5fqwlf88dtu9qa2jkvwhjr94k07cerfau3mh9s', nftAddress: 'bc1p7n462ru9wtfgclwedfgp0eqe6w40pjwt7wvkxgdmzue2y6ptdkvsuzzmu2', sign: '6b96d3f0165b11b448163825f67a894e8cb1e2fcaa44f203ce6f704c77c84c1c3b73735840b75c25b9d8b11c1448785c5f10f0d5a746f0482b95a4d2fc9f94d3' } { code: -1, msg: 'Signature.fromCompact: Expected 64-byte hex', data: null }
Can you help? @cloud6605
What's the endpoint you are using for this? Any pointers to docs about this procedure?
Bind btcAddress and nftAddress.
Thank you! So that's the endpoint I am looking for! How are you producing the signature?
Thank you! So that's the endpoint I am looking for! How are you producing the signature?
const keyPair = ECPair.fromWIF(wif);
const { address: btcAddress } = bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey! });
console.log(keyPair.publicKey!.toString('hex'));
if (!btcAddress) {
console.error('Failed to derive btcAddress from the provided private key.');
process.exit(1);
}
const nftAddress: string = 'bc1p7n462ru9wtfgclwedfgp0eqe6w40pjwt7wvkxgdmzue2y6ptdkvsuzzmu2';
if (!nftAddress) {
console.error('nftAddress must be provided.');
process.exit(1);
}
// Prepare the message
const timestamp: number = Date.now();
const message: string = `Please confirm that
Payment Address: ${nftAddress}
Ordinals Address: ${btcAddress}`;
// Sign the message
let signature: Buffer;
try {
signature = bitcoinMessage.sign(message, keyPair.privateKey!, keyPair.compressed);
} catch (error) {
console.error('Error signing the message:', (error as Error).message);
process.exit(1);
}
const signatureWithoutRecovery: Buffer = signature.slice(1);
// Convert the signature to base64
const signatureBase64: string = signatureWithoutRecovery.toString('hex');
console.log(signatureBase64.length);
console.log(signatureBase64);
@cloud6605 Am I right ?
but it's not working for me, so if you will manage it -> let me know please
Thank you! So that's the endpoint I am looking for! How are you producing the signature?
const keyPair = ECPair.fromWIF(wif); const { address: btcAddress } = bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey! }); console.log(keyPair.publicKey!.toString('hex')); if (!btcAddress) { console.error('Failed to derive btcAddress from the provided private key.'); process.exit(1); } const nftAddress: string = 'bc1p7n462ru9wtfgclwedfgp0eqe6w40pjwt7wvkxgdmzue2y6ptdkvsuzzmu2'; if (!nftAddress) { console.error('nftAddress must be provided.'); process.exit(1); } // Prepare the message const timestamp: number = Date.now(); const message: string = `Please confirm that Payment Address: ${nftAddress} Ordinals Address: ${btcAddress}`; // Sign the message let signature: Buffer; try { signature = bitcoinMessage.sign(message, keyPair.privateKey!, keyPair.compressed); } catch (error) { console.error('Error signing the message:', (error as Error).message); process.exit(1); } const signatureWithoutRecovery: Buffer = signature.slice(1); // Convert the signature to base64 const signatureBase64: string = signatureWithoutRecovery.toString('hex'); console.log(signatureBase64.length); console.log(signatureBase64);
@cloud6605 Am I right ?
but it's not working for me, so if you will manage it -> let me know please
Based on the docs you should be signing by the ordinals address (p2tr), not by the payment address. Anyway I am trying to do that but also getting the same error as you do, so there might be some issue on the unisat's API side. Btw I am also using bitcoinjs-lib, but bip322-js lib for signing the message - you also should use that because bitcoinjs-message is 4 years old and doesn't support p2tr (and you need to sign by the ordinals p2tr address).
Based on the docs you should be signing by the ordinals address (p2tr), not by the payment address. Anyway I am trying to do that but also getting the same error as you do, so there might be some issue on the unisat's API side. Btw I am also using bitcoinjs-lib, but bip322-js lib for signing the message - you also should use that because bitcoinjs-message is 4 years old and doesn't support p2tr (and you need to sign by the ordinals p2tr address).
Could you share the code?
Could you share the code?
Here it is, just be sure to get the version 6.1.6 of the bitcoinjs-lib (7 doesn't work well for me for some reason), and version 2.1.0 of ecpair.
const bitcoin = require("bitcoinjs-lib"); //version 6.1.6
const ecc = require('@bitcoinerlab/secp256k1'); //version 1.1.1
const {ECPairFactory} = require("ecpair"); //version 2.1.0
const {Signer} = require("bip322-js"); //version 2.0.0
const bip371 = require('bitcoinjs-lib/src/psbt/bip371');
bitcoin.initEccLib(ecc);
const ECPair = ECPairFactory(ecc);
const p2wpkhKey = ECPair.makeRandom();
const p2trKey = ECPair.makeRandom();
const p2wpkh = bitcoin.payments.p2wpkh({pubkey: p2wpkhKey.publicKey});
const p2tr = bitcoin.payments.p2tr({internalPubkey: bip371.toXOnly(p2trKey.publicKey)});
console.log("p2wpkh: ", p2wpkh.address);
console.log("p2tr: ", p2tr.address);
const toSignStr = `Please confirm that\nPayment Address: ${p2wpkh.address}\nOrdinals Address: ${p2tr.address}`;
const signatureBase64 = Signer.sign(p2trKey.toWIF(), p2tr.address, toSignStr);
console.log("Signature: ", signatureBase64);
console.log("Signature hex: ", Buffer.from(signatureBase64, 'base64').toString("hex"));
It prints out the signature in base64 and also in hex, you can get just the signature by stripping first 2 bytes (witness push count & signature push size) and the last 1 byte (sighash)
Could you share the code?
Here it is, just be sure to get the version 6.1.6 of the bitcoinjs-lib (7 doesn't work well for me for some reason), and version 2.1.0 of ecpair.
const bitcoin = require("bitcoinjs-lib"); //version 6.1.6 const ecc = require('@bitcoinerlab/secp256k1'); //version 1.1.1 const {ECPairFactory} = require("ecpair"); //version 2.1.0 const {Signer} = require("bip322-js"); //version 2.0.0 const bip371 = require('bitcoinjs-lib/src/psbt/bip371'); bitcoin.initEccLib(ecc); const ECPair = ECPairFactory(ecc); const p2wpkhKey = ECPair.makeRandom(); const p2trKey = ECPair.makeRandom(); const p2wpkh = bitcoin.payments.p2wpkh({pubkey: p2wpkhKey.publicKey}); const p2tr = bitcoin.payments.p2tr({internalPubkey: bip371.toXOnly(p2trKey.publicKey)}); console.log("p2wpkh: ", p2wpkh.address); console.log("p2tr: ", p2tr.address); const toSignStr = `Please confirm that\nPayment Address: ${p2wpkh.address}\nOrdinals Address: ${p2tr.address}`; const signatureBase64 = Signer.sign(p2trKey.toWIF(), p2tr.address, toSignStr); console.log("Signature: ", signatureBase64); console.log("Signature hex: ", Buffer.from(signatureBase64, 'base64').toString("hex"));
It prints out the signature in base64 and also in hex, you can get just the signature by stripping first 2 bytes (witness push count & signature push size) and the last 1 byte (sighash)
Maybe we can try with this Signer:
import {Signer as BTCSigner} from "bitcoinjs-lib/src/psbt";
Saw in some reps. You can check if you want. So you have the same error, yes ? it's really strange.
Maybe we can try with this Signer:
import {Signer as BTCSigner} from "bitcoinjs-lib/src/psbt";
That can only sign a specific hash, doesn't really help, because bip322 is about how you construct that hash (it is actually an invalid bitcoin transaction).
Saw in some reps. You can check if you want. So you have the same error, yes ? it's really strange.
Yep, if I send the hex output of the bip322-js library (full witness) I get:
{
"btcAddress": "bc1q6rx2tx2f3q6g4khpqrzqlh549emrl5qakcx42e",
"nftAddress": "bc1pgkrwm6c4g56l6jk4kpfar29nghjmzs7fmrdxmcxyk6a7dcuxlfxqd7emjc",
"sign": "01419e2ddd587ff0e23b12ef176df1d96804dfa20f1da6438c389e40656e743ebeec71e57ae46f05d365fc466b7e261e61d08d46289a38f193fd483d82bbbfd6a84501"
}
{
"code": -1,
"msg": "Invalid padding: string should have whole number of bytes",
"data": null
}
And if I send just the signature (strip first 2 bytes & last byte), I get:
{
"btcAddress": "bc1q6rx2tx2f3q6g4khpqrzqlh549emrl5qakcx42e",
"nftAddress": "bc1pgkrwm6c4g56l6jk4kpfar29nghjmzs7fmrdxmcxyk6a7dcuxlfxqd7emjc",
"sign": "9e2ddd587ff0e23b12ef176df1d96804dfa20f1da6438c389e40656e743ebeec71e57ae46f05d365fc466b7e261e61d08d46289a38f193fd483d82bbbfd6a845"
}
{
"code": -1,
"msg": "Signature.fromCompact: Expected 64-byte hex",
"data": null
}
I am also wondering why this binding procedure is even required (especially when used over the API), to me seems like just a UX hurdle.
I am also wondering why this binding procedure is even required (especially when used over the API), to me seems like just a UX hurdle.
Maybe @cloud6605 could help, for now I see only one way -> use Taproot address
If I try to to call the create bid endpoint for collections (https://open-api.unisat.io/v3/market/collection/auction/create_bid), with the following data:
I get a response saying:
What does this mean and how do I "bind first" through the API?